Data Exploration and Wrangling
Our goal in this section is to adjust or “wrangle” the data from each year into a common format so that we can combine the data sets across years for our analysis, and so that we have values in our variables that are correct and easy to interpret. We will need to understand what is the same and what is different across the data from different years, rename and recode the variables (e.g., by replacing the numbers 1 and 2 with the values “Male” and “Female” for the Sex variable), and combine the data. We will walk through these steps below.
First, let’s take a look at our data. We can get a good sense of it using the glimpse() function of the dplyr package.
Rows: 17,711
Columns: 29
$ psu <chr> "015438", "015438", "015438", "015438", "015438", "015438"…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.8745, 264.8745…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "B…
$ Qn1 <dbl> 10, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,…
$ Qn2 <dbl> 2, 1, 1, 1, 2, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2…
$ Qn3 <dbl> 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5…
$ ECIGT <dbl> 2, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 1, 2, 1…
$ ECIGAR <dbl> 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2…
$ ESLT <dbl> 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ EELCIGT <dbl> 2, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1…
$ EROLLCIGTS <dbl> 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2…
$ EFLAVCIGTS <dbl> 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ EBIDIS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ EFLAVCIGAR <dbl> 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2…
$ EHOOKAH <dbl> 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ EPIPE <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ ESNUS <dbl> 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ EDISSOLV <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CCIGT <dbl> 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CCIGAR <dbl> 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CSLT <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CELCIGT <dbl> 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CROLLCIGTS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CFLAVCIGTS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CBIDIS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CHOOKAH <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CPIPE <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CSNUS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CDISSOLV <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
Updating the set of variables and their names
The easiest way of making it so that the data from the different years can be combined is by making sure the different data sets all contain the same variables that share the same names. In addition, giving the columns informative names will help make our code more readable. Currently, it isn’t very clear what most of the variables indicate since the variable names are uninformative on their own, without the codebook.
We want to rename variables like Qn1 to something more meaningful like Age.
To do this we will use the rename() function of the dplyr package. The new name is always listed first before the =. This function will replace the old variable names with the new ones, i.e., after running the code below, there will no longer be a Qn1 variable in the data set, but there will be an Age variable instead. We will start working with the 2015 data, and then move on to the other years down below.
AVOCADO: I later learned that it is not correct that we need the same variables in the data set when using bind_rows, so why are we creating these dummy variables with NAs here? Won’t they be automatically created later in any case?
We also need to add new variables about usage of brands and specific flavors of e-cigarettes, because although later years have questions about this, this year unfortunately only has broad questions about flavors. Eventually we want to put the data from each year together, so we need the same variables for each year. Thus we need to add variables for brand and flavor to the 2015 data set that just contain missing values (NA).
To create these new variables, we will use the mutate function of the dplyr package. The mutate function can also be used to change the existing variables and create new variables from the old ones.
Now we can see how the data has changed:
Rows: 17,711
Columns: 38
$ psu <chr> "015438", "015438", "015438", "015438", "015438"…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.8745…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3",…
$ Age <dbl> 10, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 1…
$ Sex <dbl> 2, 1, 1, 1, 2, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 1, …
$ Grade <dbl> 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, …
$ ECIGT <dbl> 2, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, …
$ ECIGAR <dbl> 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ ESLT <dbl> 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, …
$ EELCIGT <dbl> 2, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, …
$ EROLLCIGTS <dbl> 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, …
$ EFLAVCIGTS <dbl> 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ EBIDIS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ EFLAVCIGAR <dbl> 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, …
$ EHOOKAH <dbl> 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, …
$ EPIPE <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ ESNUS <dbl> 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ EDISSOLV <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ CCIGT <dbl> 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ CCIGAR <dbl> 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ CSLT <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ CELCIGT <dbl> 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ CROLLCIGTS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ CFLAVCIGTS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ CBIDIS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ CHOOKAH <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ CPIPE <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ CSNUS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ CDISSOLV <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, …
$ brand_ecig <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ menthol <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ clove_spice <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ fruit <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ chocolate <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ alcoholic_drink <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ candy_dessert_sweets <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ other <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ no_use <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
The data for 2016-2018 have many common attributes, so we will want to write code that can be applied to all three data sets. To do this, we will use a function in R, which is basically a piece of code that can be applied to similar but different objects in R (e.g., the data tibbles from each of these three years). For more information on functions, see for example here.
AVOCADO: I added a link to the r4ds chapter on functions; are there other places in the case studies that we discuss functions? Or additional links or resources you want to add?
These next 3 years have the same structure for many of the questions we are interested in. For example, they all have flavor questions, but not a brand question. Moreover, their variable names are consistent across the years; for each year, we want to replace the vague question name Q50A with the value menthol in all three data sets, and the same is true for the other flavor variables. For each of these years, we also want to create a variable brand_ecig that just contains NA values.
Since we want to perform the same modifications on the data from all three years, rather than repeating the same somewhat messy piece of code three times, we can do this more efficiently if we create a function to do all of these steps at once. Then we can use the map_at() function of the purrr package to apply the function we created (for renaming variables etc.) to the data from 2016-2018. By using vars() inside of the map_at() function we can specify what tibbles within our nyts_data list we want to include or exclude.
Update_survey <- function(x) { x %>%
rename(Age=Q1,
Sex=Q2,
Grade=Q3,
menthol=Q50A,
clove_spice=Q50B,
fruit=Q50C,
chocolate=Q50D,
alcoholic_drink=Q50E,
candy_dessert_sweets=Q50F,
other=Q50G,
no_use=Q50H) %>%
mutate(brand_ecig=NA)
}
#few options to apply to the data:
#nyts_data <-nyts_data %>% map_at(vars(nyts2016, nyts2017, nyts2018), Update_survey)
#nyts_data <-nyts_data %>% map_at(c("nyts2016", "nyts2017", "nyts2018"), Update_survey)
nyts_data <-nyts_data %>% map_at(vars(-nyts2015, -nyts2019), Update_survey)
The final year, 2019, has a slightly different data structure compared to these earlier data sets. For example, it actually has a brand_ecig variable already, but does not contain a no_use variable. So we can’t use the same function for this data set, but have to write an individual code chunk.
nyts_data[["nyts2019"]] <- nyts_data[["nyts2019"]] %>%
rename(brand_ecig=Q40,
Age=Q1,
Sex=Q2,
Grade=Q3,
menthol=Q62A,
clove_spice=Q62B,
fruit=Q62C,
chocolate=Q62D,
alcoholic_drink=Q62E,
candy_dessert_sweets=Q62F,
other=Q62G) %>%
mutate(no_use="missing")
Now let’s take a look at the variable names for each of the years using the map function from purrr.
It’s looking better! There are still some differences in the set of variables in the different years, but things are much closer.
Updating Values
Now that we have made some progress on the selection and names of the variables themselves, we will work on the values contained in the different variables.
We can start with updating the values for Age and Grade, so that they are more understandable.
Recall from the codebook for this year’s data set that Age isn’t listed in the way one might expect, i.e., it is not just a number of years, but a numerically valued categorical variable.

The same is true for Grade:

This is why it is so important to always check the codebook!!
We also want to replace the value of 19 for Age to be ">18" and the value of 13 for Grade to be replaced with "Ungraded/Other" Also according to the codebooks, numeric values of 1 indicate a survey answer of FALSE, while a value of 2 indicates TRUE. Sex needs to be recoded, but it is a bit unclear if it is encoded slightly differently across years.
AVOCADO: For the Sex variable, how did you determine “It’s a bit difficult to tell if the encoding was the same across years” – I don’t see documentation of this (i.e., is this missing from the codebook somehow?), so it might be helpful to let the reader know how you figured this out. Carrie says to look at the codebooks and it will make sense; could consider screen shots. I looked at it again; the confusion seems to come from the SEX:RECODE variables, but we aren’t using those. Otherwise, I do think this could be dropped.
Let’s create a function to make all these updates except for Sex. We will use the mutate function again, as well as mutate_all and recode to replace specific values of certain variables.
Update_values <- function(x) { x %>%
mutate(Age=as.numeric(Age)+8,
Grade=as.numeric(Grade)+5)%>%
mutate(Age=as.factor(Age),
Grade=as.factor(Grade),
) %>%
mutate_all(~ replace(., . %in% c("*", "**"), NA))%>%
mutate(Age=recode(Age,
`19` = ">18",
),
Grade=recode(Grade,
`13` = "Ungraded/Other")) %>%
mutate_at(vars(starts_with("E", ignore.case = FALSE),
starts_with("C", ignore.case = FALSE)),
list(~recode(.,
`1` = TRUE,
`2` = FALSE,
.default = NA,
.missing = NA)))
}
nyts_data <-nyts_data %>% map(.,Update_values)
Now let’s update the Sex encoding:
It’s a bit difficult to tell if the encoding was the same across years, so let’s check using the count() function of the dplyr package.
According to the codebook, we should have:
1) 8,958 males in 2015 2) 10,438 males in 2016 3) 8,881 males in 2017
4) 10,069 males in 2018
5) 9,803 males in 2019
$nyts2015
# A tibble: 3 x 2
Sex n
<dbl> <int>
1 1 8958
2 2 8622
3 NA 131
$nyts2016
# A tibble: 3 x 2
Sex n
<dbl> <int>
1 1 10438
2 2 10082
3 NA 155
$nyts2017
# A tibble: 3 x 2
Sex n
<dbl> <int>
1 1 8881
2 2 8815
3 NA 176
$nyts2018
# A tibble: 3 x 2
Sex n
<dbl> <int>
1 1 10069
2 2 9920
3 NA 200
$nyts2019
# A tibble: 3 x 2
Sex n
<chr> <int>
1 .N 116
2 1 9803
3 2 9099
Thus, it looks like males were encoded as 1 for each year.
- 8,958 males in 2015 where 1 = male
- 10,438 males in 2016 where 1 = male
- 8,881 males in 2017 where 1 = male
- 10,069 males in 2018 where 1 = male
- 9,803 males in 2019 where 1 = male
$nyts2015
# A tibble: 3 x 2
Sex n
<fct> <int>
1 male 8958
2 female 8622
3 <NA> 131
$nyts2016
# A tibble: 3 x 2
Sex n
<fct> <int>
1 male 10438
2 female 10082
3 <NA> 155
$nyts2017
# A tibble: 3 x 2
Sex n
<fct> <int>
1 male 8881
2 female 8815
3 <NA> 176
$nyts2018
# A tibble: 3 x 2
Sex n
<fct> <int>
1 male 10069
2 female 9920
3 <NA> 200
$nyts2019
# A tibble: 3 x 2
Sex n
<fct> <int>
1 .N 116
2 male 9803
3 female 9099
Looks good!
The years (2016-2019) that have flavors also need the flavor data to be logical (meaning TRUE or FALSE):
Now there are just a few changes needed that are specific to 2019. Specifically, some of the 2019 questions use the values “.N”, “.S”, and “.Z” to indicate different types of missing data (see for example Q2 of the 2019 codebook); we just want them to be replaced with NA values.
nyts_data[["nyts2019"]] <- nyts_data[["nyts2019"]] %>%
mutate_all(~ replace(., . %in% c(".N",".S",".Z"), NA)) %>%
mutate(psu=as.character(psu)) %>%
mutate(brand_ecig = recode(brand_ecig,
`1` = "Other", #levels 1,8 combined to `Other`
`2` = "Blu",
`3` = "JUUL",
`4` = "Logic",
`5` = "MarkTen",
`6` = "NJOY",
`7` = "Vuse",
`8` = "Other"))
Great! Now our values don’t need to be handled any differently for any of the years, thus we can combine the data across years.
Even though we have different numbers of variables for each year, we can coerce the data to be combined into one tibble by using the bind_rows() function of dplyr. Importantly, this function does not require that the columns be the same. This will create NA values for any variable that is not present in given data frame but is present in one of the other data frames that is being combined. Note that the bind_cols() function does expect that the rows match. The .id argument will create a new variable with values to link each row to its original data frame. For more information see here.
Rows: 95,465
Columns: 41
$ year <chr> "nyts2015", "nyts2015", "nyts2015", "nyts2015", …
$ psu <chr> "015438", "015438", "015438", "015438", "015438"…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.8745…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3",…
$ Age <fct> 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, …
$ Sex <fct> female, male, male, male, female, female, male, …
$ Grade <fct> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, …
$ ECIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ ECIGAR <lgl> TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FA…
$ ESLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EELCIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ EROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EFLAVCIGTS <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, F…
$ EBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EFLAVCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, F…
$ EHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ESNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CCIGT <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CSLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CELCIGT <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, …
$ CROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CFLAVCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CSNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ brand_ecig <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ menthol <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ clove_spice <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ fruit <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ chocolate <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ alcoholic_drink <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ candy_dessert_sweets <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ other <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ no_use <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ EHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ CHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
We will want to do some of our analysis split by year, so we would like to be sure we have one variable that has the correct value for year. It looks like we just need to remove "nyts" from the year variable that we created from the names of the tibbles in our list and we should be all set. We will use another function from the stringr package to do this. The str_remove() function takes a string followed by a pattern and removes the pattern from the string.
Here is our clean and wrangled data:
Rows: 95,465
Columns: 41
$ year <dbl> 2015, 2015, 2015, 2015, 2015, 2015, 2015, 2015, …
$ psu <chr> "015438", "015438", "015438", "015438", "015438"…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.8745…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3",…
$ Age <fct> 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, …
$ Sex <fct> female, male, male, male, female, female, male, …
$ Grade <fct> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, …
$ ECIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ ECIGAR <lgl> TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FA…
$ ESLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EELCIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ EROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EFLAVCIGTS <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, F…
$ EBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EFLAVCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, F…
$ EHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ESNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CCIGT <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CSLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CELCIGT <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, …
$ CROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CFLAVCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CSNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ brand_ecig <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ menthol <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ clove_spice <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ fruit <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ chocolate <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ alcoholic_drink <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ candy_dessert_sweets <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ other <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ no_use <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ EHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ CHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
Note that there are several variables where there are similar names, but with a C compared to an E in the variable name. Those starting with C are related to questions about current usage (last 30 days), while those with an E are related to usage across the subjects whole life (“ever” usage). We will discuss these groups further below.
AVOCADO: I’m not sure where this should go, but I had the thought so I figured I’d include it. Maybe we can be more consistent about how we refer to students, subjects, respondents? Carrie suggests maybe trying to use students where we are talking about this specific data set, but respondents in the general survey weighting section.
Variable Table
Click here to see a table about the final variables in our data set.
value 1 = yes, value 2 = no
| year |
the year that the survey results from a particular student were acquired |
| psu |
the primary sampling unit for the survey weighting |
| finwgt |
the final analysis weight for the survey weighting |
| stratum |
the stratum used for variance estimation for the survey weighting |
| Age |
the age of the student when they took the survey |
| Sex |
the sex of the student when they took the survey |
| Grade |
the grade of the the student when the took the survey |
| ECIGT |
student reported having ever tried cigarette smoking, even one or two puffs |
| ECIGAR |
student reported having ever tried cigar, cigarillo, or little cigar smoking, even one or two puffs |
| ESLT |
student reported having ever tried chewing tobacco, snuff, or dip |
| EELCIGT |
student reported having ever tried e-cigarettes |
| EROLLCIGTS |
student reported having ever tried roll-your-own cigarettes |
| EFLAVCIGTS |
(2015 only) based on answer to “Which of the following tobacco products that you used in the past 30 days were flavored?” |
| EBIDIS |
student reported having ever tried bidis (small brown cigarettes wrapped in a leaf) |
| EFLAVCIGAR |
student reported having ever tried a flavored cigar (2015-2016) |
| EHOOKAH |
student reported having ever smoked tobacco from a hookah or a waterpipe |
| EPIPE |
student reported having ever smoked tobacco from a pipe (not hookah) |
| ESNUS |
student reported having ever used snus, such as Camel or Malboro Snus |
| EDISSOLV |
student reported having ever tried dissolvable tobacco products such as Ariva, Stonewall, Camel orbs, Camel sticks, Marlboro sticks, or Camel strips |
| CCIGT |
student reported they smoked cigarettes on >= 1 of the past 30 days |
| CCIGAR |
student reported they smoked cigars on >= 1 of the past 30 days |
| CSLT |
student reported they used chewing tobacco, snuff, or dip on >= 1 of the past 30 days |
| CELCIGT |
student reported they used electronic cigarettes or e-cigarettes one or more days in the past 30 |
| CROLLCIGTS |
student reported they smoked roll-your-own cigarettes during the past 30 days |
| CFLAVCIGTS |
(2015 only) based on answer to “Which of the following tobacco products that you used in the past 30 days were flavored?” |
| CBIDIS |
student reported they smoked bidis during the past 30 days |
| CHOOKAH |
student reported they smoked tobacco in a hookah on >= 1 of the past 30 days |
| CPIPE |
student reported they smoked tobacco in a pipe (not hookah) during the past 30 days |
| CSNUS |
student reported they used snus during the past 30 days |
| CDISSOLV |
student reported they used dissolvable tobacco products such as Ariva, Stonewall, Camel orbs, Camel sticks, Marlboro sticks, or Camel strips during the past 30 days |
| brand_ecig |
student answer to “During the past 30 days, what brand of e-cigarettes did you usually use?” |
| menthol |
student selected Menthol or mint as the answer to “What flavors of tobacco products have you used in the past 30 days? (select one or more)” |
| clove_spice |
student selected clove or spice as the answer to “What flavors of tobacco products have you used in the past 30 days? (select one or more)” |
| fruit |
student selected fruit as the answer to “What flavors of tobacco products have you used in the past 30 days? (select one or more)” |
| chocolate |
student selected chocolate as the answer to “What flavors of tobacco products have you used in the past 30 days? (select one or more)” |
| alcoholic_drink |
student selected alcoholic drink (such as wine, cognac, margarita, or other cocktails) as the answer to “What flavors of tobacco products have you used in the past 30 days? (choose one or more)” |
| candy_dessert_sweets |
student selected candy, desserts or other sweets as the answer to “What flavors of tobacco products have you used in the past 30 days? (choose one or more)” |
| other |
student selected some other flavor not listed as the answer to “What flavors of tobacco products have you used in the past 30 days? (choose one or more)” |
| no_use |
student reported that they did not use any flavored tobacco products in the past 30 days or did not answer the question about using flavors |
| EHTP |
student reported having ever tried heated (also known as “heat-not-burn”) tobacco products |
| CHTP |
student reported they used heated tobacco products during the past 30 days |
Data Visualization
Recall that our main questions were:
- How has tobacco and e-cigarette use by American youths changed since 2015?
- How do vaping rates compare between males and females?
What vaping brands and flavors appear to be used the most frequently?
We will base this on the following survey questions:
> “During the past 30 days, what brand of e-cigarettes did you usually use?”
>" What flavors of tobacco products have you used in the past 30 days?"
Is there a relationship between e-cigarette/vaping use and other tobacco use?
We are now going to create data visualizations to explore each of these questions.
For many of these questions we will be interested in both current and ever users, so we will want to create a variable for labeling individuals who are current users of any tobacco product (or not, i.e., who do not currently use a tobacco product) and a variable for labeling individuals who are “ever users” of any tobacco product (or not, i.e., who have never used a tobacco product).
We define these two groups as follows:
- current = students who used a product for >=1 day in the past 30 days
- ever = students who report having used or tried a product at any point in time
All current users are therefore ever users but not all ever users are current users. Thus, current users are a subset of ever users.
To add these grouping variables to our data we will do a bit more wrangling using the mutate() function again of the dplyr package. As discussed above, our data set contains a set of questions that relate to whether the student has ever used the particular tobacco product (questions that start with the letter “E”), and questions that relate to whether the student currently uses the particular tobacco product (questions that start with the letter “C”).
Here are some examples for these data entries:
- EPIPE: Students who reported they have smoked tobacco from a pipe (not hookah).
- CPIPE: Students who reported they smoked tobacco in a pipe (not hookah) during the past 30 days.
- EROLLCIGTS: RECODE: Students who reported they have tried smoking roll-your-own cigarettes.
- CROLLCIGTS: RECODE: Students who reported they smoked roll-your-own cigarettes during the past 30 days.
Based on many questions like this:
In the past 30 days, which of the following products have you used on at least one day? (Select one or more) A. Roll-your-own cigarettes
B. Pipes filled with tobacco (not hookah or waterpipe)
C. Snus, such as Camel, Marlboro, or General Snus
D. Dissolvable tobacco products such as Ariva, Stonewall, Camel orbs, Camel sticks, Marlboro sticks, or Camel strips
E. Bidis (small brown cigarettes wrapped in a leaf)
F. I have not used any of the products listed above in the past 30 days
Which of the following tobacco products have you ever tried, even just one time? (Select one or more)
A. Roll-your-own cigarettes
B. Pipes filled with tobacco (not hookah or waterpipe)
C. Snus, such as Camel, Marlboro, or General Snus
D. Dissolvable tobacco products such as Ariva, Stonewall, Camel orbs, Camel sticks, Marlboro sticks, or Camel strips
E. Bidis (small brown cigarettes wrapped in a leaf)
F. I have never tried any of the products listed above
We will sum across the variables that relate to ever or current tobacco usage questions to determine if the student answered yes to any of the ever or current questions.
We will then use the case_when() function of the dplyr package to convert the sum values to TRUE or FALSE based on the threshold of zero. If the sum is greater than zero, then we know the student answered yes to at least one question.
nyts_data <-nyts_data %>%
mutate(tobacco_sum_ever = select(., starts_with("E", ignore.case = FALSE)) %>%
base::apply(1, sum, na.rm=TRUE),
tobacco_sum_current = select(., starts_with("C", ignore.case = FALSE)) %>%
apply(1, sum, na.rm=TRUE)) %>%
mutate(tobacco_ever = case_when(tobacco_sum_ever > 0 ~ TRUE,
tobacco_sum_ever == 0 ~ FALSE),
tobacco_current = case_when(tobacco_sum_current > 0 ~ TRUE,
tobacco_sum_current == 0 ~ FALSE))
Rows: 95,465
Columns: 45
$ year <dbl> 2015, 2015, 2015, 2015, 2015, 2015, 2015, 2015, …
$ psu <chr> "015438", "015438", "015438", "015438", "015438"…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.8745…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3",…
$ Age <fct> 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, …
$ Sex <fct> female, male, male, male, female, female, male, …
$ Grade <fct> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, …
$ ECIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ ECIGAR <lgl> TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FA…
$ ESLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EELCIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ EROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EFLAVCIGTS <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, F…
$ EBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EFLAVCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, F…
$ EHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ESNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CCIGT <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CSLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CELCIGT <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, …
$ CROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CFLAVCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CSNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ brand_ecig <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ menthol <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ clove_spice <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ fruit <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ chocolate <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ alcoholic_drink <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ candy_dessert_sweets <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ other <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ no_use <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ EHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ CHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ tobacco_sum_ever <int> 1, 4, 0, 3, 0, 2, 8, 4, 0, 0, 0, 1, 1, 0, 0, 4, …
$ tobacco_sum_current <int> 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ tobacco_ever <lgl> TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE…
$ tobacco_current <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, F…
We are also interested in e-cigarette usage compared to other tobacco products, so we will create some variables related to the sum of all e-cigarette usage question variables and the sum of all tobacco usage question variables excluding those that are about e-cigarettes. There is only one variable about e-cigarette usage ever (EELCIGT) and one about current usage (CELCIGT).
nyts_data <-nyts_data %>% mutate(ecig_sum_ever = select(., EELCIGT) %>%
apply(1, sum, na.rm=TRUE),
ecig_sum_current = select(., CELCIGT) %>%
apply(1, sum, na.rm=TRUE),
non_ecig_sum_ever = select(., starts_with("E", ignore.case = FALSE)) %>%
select(.,-EELCIGT) %>%
apply(1, sum, na.rm=TRUE),
non_ecig_sum_current = select(., starts_with("C", ignore.case = FALSE)) %>%
select(.,-CELCIGT) %>%
apply(1, sum, na.rm=TRUE)) %>%
mutate(ecig_ever = case_when(ecig_sum_ever > 0 ~ TRUE,
ecig_sum_ever == 0 ~ FALSE),
ecig_current = case_when(ecig_sum_current > 0 ~ TRUE,
ecig_sum_current == 0 ~ FALSE),
non_ecig_ever = case_when(non_ecig_sum_ever > 0 ~ TRUE,
non_ecig_sum_ever == 0 ~ FALSE),
non_ecig_current = case_when(non_ecig_sum_current > 0 ~ TRUE,
non_ecig_sum_current == 0 ~ FALSE))
Rows: 95,465
Columns: 53
$ year <dbl> 2015, 2015, 2015, 2015, 2015, 2015, 2015, 2015, …
$ psu <chr> "015438", "015438", "015438", "015438", "015438"…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.8745…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3",…
$ Age <fct> 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, …
$ Sex <fct> female, male, male, male, female, female, male, …
$ Grade <fct> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, …
$ ECIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ ECIGAR <lgl> TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FA…
$ ESLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EELCIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ EROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EFLAVCIGTS <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, F…
$ EBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EFLAVCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, F…
$ EHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ESNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CCIGT <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CSLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CELCIGT <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, …
$ CROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CFLAVCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CSNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ brand_ecig <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ menthol <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ clove_spice <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ fruit <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ chocolate <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ alcoholic_drink <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ candy_dessert_sweets <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ other <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ no_use <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ EHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ CHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ tobacco_sum_ever <int> 1, 4, 0, 3, 0, 2, 8, 4, 0, 0, 0, 1, 1, 0, 0, 4, …
$ tobacco_sum_current <int> 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ tobacco_ever <lgl> TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE…
$ tobacco_current <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, F…
$ ecig_sum_ever <int> 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, …
$ ecig_sum_current <int> 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ non_ecig_sum_ever <int> 1, 3, 0, 2, 0, 1, 7, 3, 0, 0, 0, 0, 1, 0, 0, 3, …
$ non_ecig_sum_current <int> 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ ecig_ever <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ ecig_current <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, …
$ non_ecig_ever <lgl> TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE…
$ non_ecig_current <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
Finally, we are also interested in grouping students that only use e-cigarettes and those that only use other forms of tobacco.
Recall that current users are a subset of ever users, thus students would typically answer yes to having tried vaping products if they had used them one or more days in the past 30 days.
First we will make a small toy dataset called test to show what we will do with the larger dataset:
test <- tibble(ecig_ever = c("TRUE", "TRUE", "TRUE", "TRUE", "FALSE", "FALSE", "TRUE", "FALSE", "FALSE"),
non_ecig_ever = c("TRUE", "FALSE","FALSE","FALSE", "FALSE", "FALSE", "TRUE", "TRUE", "TRUE"),
ecig_current = c("TRUE", "FALSE","FALSE", "TRUE", "TRUE", "FALSE", "FALSE", "FALSE", "FALSE"),
non_ecig_current = c("TRUE", "FALSE","TRUE", "FALSE", "TRUE", "FALSE", "FALSE", "FALSE", "TRUE"))
test
# A tibble: 9 x 4
ecig_ever non_ecig_ever ecig_current non_ecig_current
<chr> <chr> <chr> <chr>
1 TRUE TRUE TRUE TRUE
2 TRUE FALSE FALSE FALSE
3 TRUE FALSE FALSE TRUE
4 TRUE FALSE TRUE FALSE
5 FALSE FALSE TRUE TRUE
6 FALSE FALSE FALSE FALSE
7 TRUE TRUE FALSE FALSE
8 FALSE TRUE FALSE FALSE
9 FALSE TRUE FALSE TRUE
Now, let’s look at identifying students who have tried e-cigarettes, but are not current users, and who have never tried other tobacco products (and are therefore not current users). We will again use the case_when() and the mutate function to create new variables with specific values when certain conditions are met. In this case, we will specify that several conditions must be met by using the & symbol. For a value of TRUE for the new ecig_only_ever variable, all of the conditions combined with & must be met. If any of the conditions are not met then the ecig_only_ever value will be FALSE based on the last line TRUE ~ FALSE.
# A tibble: 9 x 5
ecig_ever non_ecig_ever ecig_current non_ecig_current ecig_only_ever
<chr> <chr> <chr> <chr> <lgl>
1 TRUE TRUE TRUE TRUE FALSE
2 TRUE FALSE FALSE FALSE TRUE
3 TRUE FALSE FALSE TRUE FALSE
4 TRUE FALSE TRUE FALSE FALSE
5 FALSE FALSE TRUE TRUE FALSE
6 FALSE FALSE FALSE FALSE FALSE
7 TRUE TRUE FALSE FALSE FALSE
8 FALSE TRUE FALSE FALSE FALSE
9 FALSE TRUE FALSE TRUE FALSE
We can see from the second row, that the ecig_only_ever is TRUE when we would expect it to be. We can also see from the fourth row, that even though the student reported yes to ever trying e-cigarettes, because they also reported yes to currently using e-cigarettes the value for only ever trying e-cigarettes is FALSE. Additionally we can see from the seventh row that similarly even though the student reported yest to ever trying e-cigarettes, they also reported yes to ever trying other products, and the value for only ever trying e-cigarettes is FALSE. Importantly, we can see from the 6th row, that if all responses are negative than the value is FALSE.
Now we will expand this to the other possible categories. In this case we note that since current users are a subset of ever users, it doesn’t matter if a user reports yes to ever trying e-cigarettes, they can still be a current user.
Rows: 9
Columns: 9
$ ecig_ever <chr> "TRUE", "TRUE", "TRUE", "TRUE", "FALSE", "FALSE…
$ non_ecig_ever <chr> "TRUE", "FALSE", "FALSE", "FALSE", "FALSE", "FA…
$ ecig_current <chr> "TRUE", "FALSE", "FALSE", "TRUE", "TRUE", "FALS…
$ non_ecig_current <chr> "TRUE", "FALSE", "TRUE", "FALSE", "TRUE", "FALS…
$ ecig_only_ever <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ecig_only_current <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,…
$ non_ecig_only_ever <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ non_ecig_only_current <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ no_use <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE,…
Take a minute to check that the values are what we would expect.
OK, now we are going to make a Group variable based on the new variables we just made to classify students into one of four mutually exclusive and exhaustive categories. In this case we will have a particular value based on one condition or another. This or conditional is specified by the | symbol. Only one of the conditions needs to exist for that particular value, whereas when we used the & symbol, all of the conditions had to be met. If a student has ever tried or currently uses e-cigarettes, but has never tried other tobacco products, the value will be Only e-cigarettes. If a student has ever tried or is a current user of other tobacco products, but has never tried e-cigarettes, the value will be Only other products. If the value of the no_use variable is simply TRUE, then the Group variable value will be Neither. Finally, if a student has tried or currently uses both e-cigarettes and other tobacco products the Group variable value will be Combination of products. Therefore the values for the usage of the variables based on only using e-cigarettes or only other products will all be FALSE. Of course the student will also have had to answer yes to any of the use-based questions, thus the no_use variable would also need to be FALSE.
AVOCADO: Consider dropping the last two sentences in the paragraph above? i.e., from “Therefore the values…” to “would also need to be FALSE.” I’m not sure what they are adding. LEAVE IN FOR CARRIE TO REVIEW.
# A tibble: 4 x 2
Group n
<chr> <int>
1 Combination of products 4
2 Neither 1
3 Only e-cigarettes 2
4 Only other products 2
Rows: 9
Columns: 10
$ ecig_ever <chr> "TRUE", "TRUE", "TRUE", "TRUE", "FALSE", "FALSE…
$ non_ecig_ever <chr> "TRUE", "FALSE", "FALSE", "FALSE", "FALSE", "FA…
$ ecig_current <chr> "TRUE", "FALSE", "FALSE", "TRUE", "TRUE", "FALS…
$ non_ecig_current <chr> "TRUE", "FALSE", "TRUE", "FALSE", "TRUE", "FALS…
$ ecig_only_ever <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ecig_only_current <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,…
$ non_ecig_only_ever <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ non_ecig_only_current <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ no_use <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE,…
$ Group <chr> "Combination of products", "Only e-cigarettes",…
OK, now that we have seen how this works with our toy dataset, we will apply our code to our nyts_data.
nyts_data %<>%
mutate(ecig_only_ever = case_when(ecig_ever == TRUE &
non_ecig_ever == FALSE &
ecig_current == FALSE &
non_ecig_current == FALSE ~ TRUE,
TRUE ~ FALSE),
ecig_only_current = case_when(ecig_current == TRUE &
non_ecig_ever == FALSE &
non_ecig_current == FALSE ~ TRUE,
TRUE ~ FALSE),
non_ecig_only_ever = case_when(non_ecig_ever == TRUE &
ecig_ever == FALSE &
ecig_current == FALSE &
non_ecig_current == FALSE ~ TRUE,
TRUE ~ FALSE),
non_ecig_only_current = case_when(non_ecig_current == TRUE &
ecig_ever == FALSE &
ecig_current == FALSE ~ TRUE,
TRUE ~ FALSE),
no_use = case_when(non_ecig_ever == FALSE &
ecig_ever == FALSE &
ecig_current == FALSE &
non_ecig_current == FALSE ~TRUE,
TRUE ~ FALSE)) %>%
mutate(Group = case_when(ecig_only_ever == TRUE |
ecig_only_current == TRUE ~ "Only e-cigarettes",
non_ecig_only_ever == TRUE |
non_ecig_only_current == TRUE ~ "Only other products",
no_use == TRUE ~ "Neither",
ecig_only_ever == FALSE &
ecig_only_current == FALSE &
non_ecig_only_ever == FALSE &
non_ecig_only_current == FALSE &
no_use == FALSE ~ "Combination of products"))
Lastly, it can be very helpful to have the total number of students surveyed each year. We can easily add a variable for this by using the add_count() function of the dplyr package. This will create a variable called n which will show the total number of survey responses for that year.
Rows: 95,465
Columns: 59
$ year <dbl> 2015, 2015, 2015, 2015, 2015, 2015, 2015, 2015,…
$ psu <chr> "015438", "015438", "015438", "015438", "015438…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.874…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3"…
$ Age <fct> 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,…
$ Sex <fct> female, male, male, male, female, female, male,…
$ Grade <fct> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,…
$ ECIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TR…
$ ECIGAR <lgl> TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, F…
$ ESLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,…
$ EELCIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TR…
$ EROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,…
$ EFLAVCIGTS <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, …
$ EBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ EFLAVCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ EPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ ESNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,…
$ EDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CCIGT <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CSLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CELCIGT <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,…
$ CROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CFLAVCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CSNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ brand_ecig <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ menthol <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ clove_spice <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ fruit <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ chocolate <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ alcoholic_drink <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ candy_dessert_sweets <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ other <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ no_use <lgl> FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, …
$ EHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ CHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ tobacco_sum_ever <int> 1, 4, 0, 3, 0, 2, 8, 4, 0, 0, 0, 1, 1, 0, 0, 4,…
$ tobacco_sum_current <int> 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ tobacco_ever <lgl> TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ tobacco_current <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, …
$ ecig_sum_ever <int> 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1,…
$ ecig_sum_current <int> 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ non_ecig_sum_ever <int> 1, 3, 0, 2, 0, 1, 7, 3, 0, 0, 0, 0, 1, 0, 0, 3,…
$ non_ecig_sum_current <int> 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ ecig_ever <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TR…
$ ecig_current <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,…
$ non_ecig_ever <lgl> TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ non_ecig_current <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ecig_only_ever <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ ecig_only_current <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ non_ecig_only_ever <lgl> TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ non_ecig_only_current <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ Group <chr> "Only other products", "Combination of products…
$ n <int> 17711, 17711, 17711, 17711, 17711, 17711, 17711…
Question 1
Recall that we are interested in investigating how vaping product use has compared with other tobacco use over time. To answer this, we first want to get a sense of how tobacco use has changed in general since 2015.
To create a visualization of how tobacco usage has changed over time, we will first convert the usage data to a percent value for each year, telling us what percent of respondents fall into a particular usage category. To do this we will use the group_by() and summarize() functions of the dplyr package. This will create new variables which we will name Ever and Current based on the percentages of TRUE values for tobacco_ever and tobacco_current for each year. In this case the mean() function is used to calculate the percentages based on an automatic conversion that R does where for TRUE/FALSE variables, TRUE is given a value of one and FALSE is given a value of zero. The mean of a 0-1 binary variable is just the percent of the time the value is 1. NA values do not contribute to the total count when we include the argument na.rm = TRUE to our function call.
Click here to see a toy example:
# A tibble: 10 x 1
var1
<lgl>
1 TRUE
2 TRUE
3 TRUE
4 FALSE
5 FALSE
6 FALSE
7 FALSE
8 FALSE
9 FALSE
10 FALSE
# A tibble: 1 x 1
Percentage
<dbl>
1 30
# A tibble: 10 x 1
var1
<lgl>
1 TRUE
2 TRUE
3 TRUE
4 FALSE
5 FALSE
6 FALSE
7 NA
8 NA
9 NA
10 NA
# A tibble: 1 x 1
Percentage
<dbl>
1 50
And now back to our data:
# A tibble: 5 x 3
year Ever Current
<dbl> <dbl> <dbl>
1 2015 36.8 18.0
2 2016 33.4 14.0
3 2017 31.8 14.4
4 2018 34.7 18.7
5 2019 39.7 22.4
We will use the pivot_longer function to take all columns except year (in this case the Ever and Current columns), to create a column called User that will contain the current column name information and a column called Percentage of students which will contain the mean percentage values that we just calculated. This converts our data into a format called “long” format.
# A tibble: 10 x 3
year User `Percentage of students`
<dbl> <chr> <dbl>
1 2015 Ever 36.8
2 2015 Current 18.0
3 2016 Ever 33.4
4 2016 Current 14.0
5 2017 Ever 31.8
6 2017 Current 14.4
7 2018 Ever 34.7
8 2018 Current 18.7
9 2019 Ever 39.7
10 2019 Current 22.4
You may have noticed that our data is longer than it used to be! Hence the name of the function pivot_longer(). Data is often easier to plot when it is in this format.
Now we will use this data to create a plot using the ggplot2 package.
The first thing we do to create a plot is specify what data we are using for our x axis and y axis with theaes() argument of the ggplot() function. Then we add layers to our plot that specify what type of plot we would like to create. We can use the geom_line() function to create lines for each type of user. We specify that we want to use different line types for each user using aes(). We will also add points to our lines using the geom_point() function. We can add additional layers to specify colors and details about labels and legends etc.
plot1 <- nyts_data %>%
dplyr::group_by(year) %>%
dplyr::summarize(Ever=(mean(tobacco_ever, na.rm = TRUE)*100),
Current=(mean(tobacco_current, na.rm = TRUE)*100))%>%
pivot_longer(cols = -year, names_to = "User", values_to = "Percentage of students")%>%
ggplot(aes(x=year,y=`Percentage of students`)) +
geom_line(aes(linetype=User)) +
geom_point(show.legend = FALSE, size = 2) +
# this allows us to choose what type of line we want for each line
scale_linetype_manual(values = c(2,1)) +
# this allows us to specify how the y-axis should appear
scale_y_continuous(breaks = seq(0,70,by=10),
labels = seq(0,70,by=10),
limits = c(0,70)) +
#this adjusts the background style of the plot
theme_linedraw() +
# this moves the legend to the bottom of the plot and removes the x axis title
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How has tobacco use varied over the years?",
y = "% of students")
plot1

Nice! Now we can see how overall tobacco usage has changed since 2017. It appears that usage first decreased from 2015 to 2017 and then increased a bit since 2017, surpassing the levels in 2015.
What about e-cigarette use? How has the usage of e-cigarettes changed over time?
plot1a <- nyts_data %>%
dplyr::group_by(year) %>%
dplyr::summarize(Ever=(mean(ecig_ever, na.rm = TRUE)*100),
Current=(mean(ecig_current, na.rm = TRUE)*100))%>%
pivot_longer(cols = -year, names_to = "User", values_to = "Percentage of students")%>%
ggplot(aes(x=year,y=`Percentage of students`)) +
geom_line(aes(linetype=User)) +
geom_point(show.legend = FALSE, size = 2) +
# this allows us to choose what type of line we want for each line
scale_linetype_manual(values = c(2,1)) +
# this allows us to specify how the y-axis should appear
scale_y_continuous(breaks = seq(0,60,by=10),
labels = seq(0,60,by=10),
limits = c(0,60)) +
#this adjusts the background style of the plot
theme_linedraw() +
# this moves the legend to the bottom of the plot and removes the x axis title
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How has e-cigarette use varied over the years?",
y = "% of students")
plot1a
It looks like the shape of the plot is very similar to tobacco usage overall. We see a downward trend until 2017 when the rate of both current and ever users increased. Recall that this is in agreement with the articles that we referenced earlier. We can see that the slope looks steeper for e-cigarette usage as compared to all tobacco products (including e-cigarettes).
Now let’s plot this data together on the same plot.
We will have four groups (e-cigarette ever users, e-cigarette current users, tobacco ever users, and tobacco current users) to plot, therefore, it would be useful to add color to our plot. Keep in mind that e-cigarette users are a subset of any tobacco product users.
One important thing to keep in mind when creating plots is that individuals with color blindness may have a difficult time distinguishing groups when certain color choices are used.
One great option is to use the viridis package, which offers color palettes with colors that are still distinguishable by individuals with most forms of color blindness.
We can choose which colors we want to use by using the show_col() function of the scales package.
Here are some color options:

We will select the first and fourth colors for our plot. To add these specific colors we will use the scale_color_manual() function of the ggplot2 package.
We will calculate the mean ever and current usage percentages for students who used e-cigarettes or any tobacco products (including e-cigarettes) for each year again using the group_by() and summarize() functions. We will again use the pivot_longer function to convert our data to long format. We will also use the separate() function of the tidyr package to create two variables from one of the variables. This is done by separating by, in this case, an underscore.
nyts_data %>%
dplyr::group_by(year) %>%
dplyr::summarize("Ever_Any Tobacco Product \n (including e-cigarettes)"=(mean(tobacco_ever, na.rm = TRUE)*100),
"Current_Any Tobacco Product \n (including e-cigarettes)"=(mean(tobacco_current, na.rm = TRUE)*100),
"Ever_E-cigarettes"=(mean(ecig_ever, na.rm = TRUE)*100),
"Current_E-cigarettes"=(mean(ecig_current, na.rm = TRUE)*100))%>%
pivot_longer(cols = -year, names_to = "User", values_to = "Percentage of students")%>%
separate(User, into = c("User", "Product"), sep = "_")%>%
head()
# A tibble: 6 x 4
year User Product `Percentage of studen…
<dbl> <chr> <chr> <dbl>
1 2015 Ever "Any Tobacco Product \n (including e-cig… 36.8
2 2015 Current "Any Tobacco Product \n (including e-cig… 18.0
3 2015 Ever "E-cigarettes" 26.4
4 2015 Current "E-cigarettes" 11.0
5 2016 Ever "Any Tobacco Product \n (including e-cig… 33.4
6 2016 Current "Any Tobacco Product \n (including e-cig… 14.0
plot1t <- nyts_data %>%
dplyr::group_by(year) %>%
dplyr::summarize("Ever_Any Tobacco Product \n (including e-cigarettes)"=(mean(tobacco_ever, na.rm = TRUE)*100),
"Current_Any Tobacco Product \n (including e-cigarettes)"=(mean(tobacco_current, na.rm = TRUE)*100),
"Ever_E-cigarettes"=(mean(ecig_ever, na.rm = TRUE)*100),
"Current_E-cigarettes"=(mean(ecig_current, na.rm = TRUE)*100))%>%
pivot_longer(cols = -year, names_to = "User", values_to = "Percentage of students")%>%
separate(User, into = c("User", "Product"), sep = "_")%>%
ggplot(aes(x=year,y=`Percentage of students`, color = Product)) +
geom_line(aes(linetype=User)) +
geom_point(show.legend = FALSE, size = 2) +
# this allows us to choose what type of line we want for each line
scale_linetype_manual(values = c(2,1)) +
# we want purple associated with e-cigarettes to be consistent with later plots
scale_color_manual(values = rev(v_colors))+
# this allows us to specify how the y-axis should appear
scale_y_continuous(breaks = seq(0,60,by=10),
labels = seq(0,60,by=10),
limits = c(0,60)) +
#this adjusts the background style of the plot
theme_linedraw() +
# this moves the legend to the bottom of the plot and removes the x axis title
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How has tobacco use varied over the years?",
y = "% of students")
plot1t

We see an increase in all categories starting in 2017, but the rate of increase is higher for students using only e-cigarettes (current or ever users), as shown by the higher slope of the e-cigarette lines.
In the above plots, the “Any tobacco product” groups include individuals in the “E-cigarette only” groups. Now let’s plot students in two mutually exclusive groups on the same plot: those who reported either using only e-cigarettes or only other tobacco products (besides e-cigarettes), but not both.
We will calculate the mean ever and current usage percentages for students in these two mutually exclusive groups, again using the group_by() function and the summarize() function. We will again use the pivot_longer function to convert our data to long format. We will also again use the separate() function of the tidyr package to create two variables from one variable. This is done by separating by, in this case, a space.
nyts_data %>%
dplyr::group_by(year) %>%
dplyr::summarize("Ever_E-cigarette"=(mean(ecig_only_ever, na.rm = TRUE)*100),
"Current_E-cigarette"=(mean(ecig_only_current, na.rm = TRUE)*100),
"Ever_Non-e-cigarette" =(mean(non_ecig_only_ever, na.rm = TRUE)*100),
"Current_Non-e-cigarette"=(mean(non_ecig_only_current, na.rm = TRUE)*100)) %>%
pivot_longer(cols = -year, names_to = "User", values_to = "Percentage of students") %>%
tidyr::separate(User, into = c("User", "Product"), sep = "_") %>%
head()
# A tibble: 6 x 4
year User Product `Percentage of students`
<dbl> <chr> <chr> <dbl>
1 2015 Ever E-cigarette 4.36
2 2015 Current E-cigarette 1.54
3 2015 Ever Non-e-cigarette 7.06
4 2015 Current Non-e-cigarette 3.35
5 2016 Ever E-cigarette 4.54
6 2016 Current E-cigarette 1.23
plot1c <- nyts_data %>%
dplyr::group_by(year) %>%
dplyr::summarize("Ever_E-cigarette"=(mean(ecig_only_ever, na.rm = TRUE)*100),
"Current_E-cigarette"=(mean(ecig_only_current, na.rm = TRUE)*100),
"Ever_Non-e-cigarette" =(mean(non_ecig_only_ever, na.rm = TRUE)*100),
"Current_Non-e-cigarette"=(mean(non_ecig_only_current, na.rm = TRUE)*100))%>%
pivot_longer(cols = -year, names_to = "User", values_to = "Percentage of students")%>%
separate(User, into = c("User", "Product"), sep = "_") %>%
ggplot(aes(x=year,y=`Percentage of students`, color = Product)) +
geom_line(aes(linetype=User)) +
geom_point(show.legend = FALSE, size = 2) +
# this allows us to choose what type of line we want for each line
scale_linetype_manual(values = c(2,1)) +
# this allows us to specify how the y-axis should appear
scale_y_continuous(breaks = seq(0,30,by=10),
labels = seq(0,30,by=10),
limits = c(0,30)) +
scale_color_manual(values = v_colors)+
#this adjusts the background style of the plot
theme_linedraw() +
# this moves the legend to the bottom of the plot and removes the x axis title
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How has use of only e-cigarettes and \n only tobacco products besides e-cigarettes varied over time?",
y = "% of students")
plot1c

Very interesting! We can see from this plot that the percentage of students who had currently used (or ever tried) only e-cigarettes greatly increased starting in 2017, while in contrast the percentage of students who had ever tried only non-e-cigarette tobacco products actually diminished over time. In fact, we can see that in 2019 the percentage of students who were current e-cigarette users surpassed the percentage that had tried a non-e-cigarette product even just once.
Recall that we made a variable called Group that identified students who used either just e-cigarette products, just other tobacco products (besides e-cigarettes), or students who used both e-cigarettes and some other type of tobacco product.
# A tibble: 4 x 2
Group n
<chr> <int>
1 Combination of products 315716730
2 Neither 1183798832
3 Only e-cigarettes 151032421
4 Only other products 179275592
We will now make a plot over time of each of these groups. Since we will have 4 total groups, we will use 4 of the viridis colors. Notice, that in this case we are grouping by three variables by simply separating the variables that we want to group by with a comma in our group_by() function like this: group_by(Group, year, n).
# A tibble: 6 x 5
# Groups: Group, year [6]
Group year n group_count `Percentage of students`
<chr> <dbl> <int> <int> <dbl>
1 Combination of products 2015 17711 3634 20.5
2 Combination of products 2016 20675 3297 15.9
3 Combination of products 2017 17872 2623 14.7
4 Combination of products 2018 20189 3321 16.4
5 Combination of products 2019 19018 3642 19.2
6 Neither 2015 17711 11188 63.2

We can see that the majority of students did not report using any tobacco products. Of the students that did report using tobacco products, the majority of the students used both e-cigarettes and some other tobacco product. Again, a much larger percentage reported using only e-cigarettes rather than only other tobacco products in 2019.
We will further explore the relationship between e-cigarette usage and other tobacco products a bit later in the case study.
Question 2
Now we want to look how e-cigarette smoking rates compare between males and females across time.
We will calculate the percent ever and current e-cigarette users for each year and sex category again using the group_by() function and the summarize() function. We will again use the pivot_longer function to convert our data to long format. Because there are some missing values for the Sex variable, we will filter these out; based on the codebook, there is little information about why these values are missing, so our survey data only allows us to consider two reported sex values with confidence.
AVOCADO: Carrie, I am filtering out the NAs for Sex now; can you check/modify the language I included above? I feel like you put it more eloquently on the phone.
AVOCADO: Also, in this plot title e-cigarette is changed to vaping – is that on purpose? Should we make that change earlier or throughout the case study? Or stick with e-cigarette?
# A tibble: 6 x 4
# Groups: year [2]
year Sex User `Percentage of students`
<dbl> <fct> <chr> <dbl>
1 2015 male Ever 29.3
2 2015 male Current 13.3
3 2015 female Ever 24.3
4 2015 female Current 9.05
5 2016 male Ever 24.1
6 2016 male Current 8.72
plot2 <- nyts_data %>%
filter(!is.na(Sex)) %>%
group_by(year, Sex) %>%
summarize(Ever=(mean(EELCIGT, na.rm = TRUE)*100),
Current=(mean(CELCIGT, na.rm = TRUE)*100))%>%
# filter(!is.na(Sex)) %>%
pivot_longer(cols = Ever:Current,
names_to = "User",
values_to = "Percentage of students") %>%
ggplot(aes(x = year,y =`Percentage of students`, color = Sex)) +
geom_line(aes(linetype = User)) +
geom_point(show.legend = FALSE, size = 2) +
scale_linetype_manual(values = c(2,1)) +
scale_color_manual(values =v_colors)+
theme_linedraw() +
theme(legend.position = "bottom",
# axis.text.x = element_text(angle = 90),
axis.title.x = element_blank()) +
labs(title = "How do vaping rates compare between males and females?",
subtitle = "Current and ever users by sex",
y = "% of students")
plot2

It looks like the rates are fairly similar between the sexes, however the rate for males appears to be consistently higher across time.
Question 3
We are also interested in what vaping brands and flavors appear to be used the most frequently. Only the 2019 data set has this information. Therefore, we will filter for just this year using the filter() function of the dplyr package. We will use the summarize() function slightly differently this time, to calculate the total number of students using each brand using the n() function and the sum() function to calculate the percent for each brand based on the counts. We will also reorder the factor levels for the brand names so that they are in descending order of percent use, using the fct_reorder() function from dplyr. This will make them appear in decreasing order of percent use on the plot.
We will make a bar plot this time by using geom_bar. Importantly we assign the stat argument to identity, so that we are using the percentages that we calculated not the counts which is what is used by default. When color in specified outside of the aes() argument, this determines the border color of the bars, which in this case will be black.
# A tibble: 7 x 4
brand_ecig n total Percent
<fct> <int> <int> <dbl>
1 Blu 111 3604 3.08
2 JUUL 2028 3604 56.3
3 Logic 36 3604 0.999
4 MarkTen 32 3604 0.888
5 NJOY 44 3604 1.22
6 Other 1253 3604 34.8
7 Vuse 100 3604 2.77

Juul appears to be the most widely used brand. This is in agreement with a recent article, whose most recent data was from 2017:
We are also interested in how the usage of different flavors has changed over time.
To evaluate this we will calculate the percentage of students using each flavor each year - this includes usage of any type of flavored tobacco product. We will exclude 2015 data, as no specific flavor questions were asked at that time.
Recall that NA values are not included in calculating the total count for our percentages. However all of these flavor questions had complete reporting and did not have NA values. Therefore, these values reflect the percentage of students reporting using a particular favor out of all students surveyed (including those that did not use any tobacco products). Also students were allowed to select more than one flavor. You can see whether these variables had complete reporting by checking the NA values using the base summary function. Alternatively you can create a visual representation using the vis_miss() function of the naniar package.

The plot above confirms that these variables have no NA values (because all fields indicate 100% of data is present).
plot4 <- nyts_data %>%
filter(year!=2015) %>%
group_by(year) %>%
summarize(Menthol = (mean(menthol)*100),
`Clove or Spice` = (mean(clove_spice)*100),
Fruit = (mean(fruit)*100),
Chocolate = (mean(chocolate)*100),
`Alcoholic Drink` = (mean(alcoholic_drink)*100),
`Candy/Desserts/Sweets` = (mean(candy_dessert_sweets)*100),
Other = (mean(other)*100)) %>%
pivot_longer(cols = - year, names_to = "Flavor", values_to = "Percentage of students") %>%
rename(Year = year) %>%
ggplot(aes(y = `Percentage of students`,
x = Year,
fill = reorder(Flavor, `Percentage of students`)))+
geom_bar(stat = "identity", position = "dodge", color = "black")+
scale_fill_viridis(discrete=TRUE)+
theme_linedraw() +
guides(fill=guide_legend("Flavor"))+
labs(title = "What flavors appear to be used the most frequently?",
subtitle = "Flavors of tobacco products used in the past 30 days")
plot4

From this plot, we can see that fruit flavors are the most widely used products, followed by menthol or mint flavored products. We can also see that there was a general increase in the usage of flavored products over time.
We will now look specifically at the usage of flavored e-cigarette products vs other flavored tobacco products.
Recall that we made a variable called Group that identified students who used either just e-cigarette/vaping products, just other tobacco products (besides e-cigarettes), or students who used both e-cigarettes and some other type of tobacco product. We will compare the usage of these flavors for these different groups. We also perform some data summaries to decide how to order the panels (flavors) for display.
v_colors = viridis(5)[1:4]
plot5 <- nyts_data %>%
filter(year != 2015) %>%
group_by(year, Group) %>%
summarize(Menthol = (mean(menthol)*100),
`Clove or Spice` = (mean(clove_spice)*100),
Fruit = (mean(fruit)*100),
Chocolate = (mean(chocolate)*100),
`Alcoholic Drink` = (mean(alcoholic_drink)*100),
`Candy/Desserts/\nSweets` = (mean(candy_dessert_sweets)*100),
Other = (mean(other)*100),
Respondents = n()) %>%
#converting all columns between and including Menthol and Other to one column called Flavor
pivot_longer(cols = Menthol:Other, names_to = "Flavor", values_to = "Percentage of students") %>%
group_by(Flavor) %>%
# calculate the count of students in the year/group combination who used that flavor
mutate(affirmative=(Respondents * `Percentage of students`)/100) %>%
# calculate the fraction of total respondents who used that flavor
mutate(flavor_mean = sum(affirmative)/sum(Respondents)) %>%
ungroup() %>%
# reorder the levels of Flavor to be in increasing order of percent of students who used that flavor
mutate(flavor_mean_rank = dense_rank(flavor_mean),
Flavor = fct_reorder(Flavor, flavor_mean_rank)) %>%
ggplot(aes(x=year, y=`Percentage of students`, color=Group)) +
facet_grid(~Flavor)+
geom_line() +
geom_point(show.legend = FALSE, size = 2) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "bottom",
axis.title.x = element_blank(),
axis.text.x = element_text(angle = 90),
strip.text.x = element_text(size = 10, face = "bold")) +
labs(title = "Among different product users, what flavors are most frequently used?")
plot5

We can see from this plot that there has been an increase in the number of students reporting using flavored tobacco products. Users who use both e-cigarettes and other tobacco products appear to report using flavored products the most, followed by users who only use e-cigarettes.
Question 4
Is there a relationship between vaping rates and tobacco use? Now we will investigate the usage of e-cigarettes compared to other tobacco products in greater depth.
First let’s take a look at how e-cigarette usage and cigarette usage compare. We will select the data that specifically has to do with these products.
v_colors = viridis(6)[c(1,4)]
nyts_data %>%
group_by(year) %>%
summarize("Cigarettes, Ever" = (mean(ECIGT, na.rm = TRUE)*100),
"E-cigarettes, Ever" = (mean(EELCIGT, na.rm = TRUE)*100),
"Cigarettes, Current" = (mean(CCIGT, na.rm = TRUE)*100),
"E-cigarettes, Current" = (mean(CELCIGT, na.rm = TRUE)*100)) %>%
pivot_longer(cols= -year, names_to = "Category", values_to = "Percentage of students") %>%
separate( Category, into= c("Product", "User"), sep = ", ") %>%
head()
# A tibble: 6 x 4
year Product User `Percentage of students`
<dbl> <chr> <chr> <dbl>
1 2015 Cigarettes Ever 21.3
2 2015 E-cigarettes Ever 26.9
3 2015 Cigarettes Current 6.23
4 2015 E-cigarettes Current 11.2
5 2016 Cigarettes Ever 19.1
6 2016 E-cigarettes Ever 22.1
plot6 <- nyts_data %>%
group_by(year) %>%
summarize("Cigarettes, Ever" = (mean(ECIGT, na.rm = TRUE)*100),
"E-cigarettes, Ever" = (mean(EELCIGT, na.rm = TRUE)*100),
"Cigarettes, Current" = (mean(CCIGT, na.rm = TRUE)*100),
"E-cigarettes, Current" = (mean(CELCIGT, na.rm = TRUE)*100)) %>%
pivot_longer(cols= -year, names_to = "Category", values_to = "Percentage of students")%>%
separate( Category, into= c("Product", "User"), sep = ", ") %>%
ggplot(aes(x=year,y=`Percentage of students`, color = Product, linetype = User)) +
geom_line() +
geom_point(show.legend = FALSE, size = 2) +
scale_linetype_manual(values = c(2,1)) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How does e-cigarette use compare to cigarette use?",
subtitle = "Current and ever users of e-cigarettes and cigarettes",
y = "% of students")
plot6

Interesting! we can see that in 2019 the percentage of students that reported currently using e-cigarettes had surpassed those that ever tried (even just once) a cigarette. Overall cigarette usage appears to be declining over time. This is not the case for e-cigarettes.
Now we will look at students who reported that they had ever tried e-cigarettes or non-cigarette products. In this case we will not separate out users who specifically only used one or the other. Therefore, the students included in this plot who reported as having ever tried e-cigarettes might also be current users of non-e-cigarette products or may have at least tried non-e-cigarette products.
v_colors = viridis(6)[c(1,4)]
plot7 <- nyts_data %>%
group_by(year) %>%
summarize(`e-cigarette_ever`= (mean(ecig_ever, na.rm = TRUE)*100),
`non-e-cigarette_ever`= (mean(non_ecig_ever, na.rm = TRUE)*100)) %>%
pivot_longer(cols = -year, names_to = "Category", values_to = "Percentage of students") %>%
separate(Category, into = c("Product", "User"), sep = "_") %>%
ggplot(aes(x=year,y=`Percentage of students`, color=Product)) +
geom_line() +
geom_point(show.legend = FALSE, size = 2) +
scale_color_manual(values = v_colors) +
scale_y_continuous(breaks = seq(0, 60, by = 10), limits = c(0,60)) +
theme_linedraw() +
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How does the rate of ever trying e-cigarettes \ncompare to ever trying other products over time?",
y = "% of students")
plot7

Now we will do the same, but for students who reported currently using e-cigarettes or non-e-cigarette products.
v_colors = viridis(6)[c(1,4)]
plot8 <- nyts_data %>%
group_by(year) %>%
summarize(`e-cigarette_current`= (mean(ecig_current, na.rm = TRUE)*100),
`non-e-cigarette_current`= (mean(non_ecig_current, na.rm = TRUE)*100)) %>%
pivot_longer(cols = -year, names_to = "Category", values_to = "Percentage of students") %>%
separate(Category, into = c("Product", "User"), sep = "_") %>%
ggplot(aes(x=year, y=`Percentage of students`, color=Product)) +
geom_line(linetype = "dashed") +
geom_point(show.legend = FALSE, size = 2) +
scale_color_manual(values = v_colors) +
scale_linetype_manual(values = c(1)) +
scale_y_continuous(breaks = seq(0, 60, by = 10), limits = c(0,60)) +
theme_linedraw() +
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How does the rate of currently using e-cigarettes \ncompare to currently using other products over time?",
y = "% of students")
plot8

Putting plots together
Now we will put these plots together using the plot_grid() function of the cowplot package. We will also modify the labels using the ggdraw() function, which is also part of the cowplot package.
plotA_uw <- plot1 +
theme(axis.title.x = element_blank(),
legend.position = "none") +
labs(title = "Tobacco product users more prevalent after 2017",
subtitle = NULL,
y = "% of students")
plotB_uw <- plot7 +
theme(axis.title.x = element_blank(),
legend.position = "none") +
labs(title = "% Ever trying e-cigarettes increases &\n% Ever trying other products decreases",
subtitle = NULL,
y = "% of students")
plotC_uw <- plot8 +
theme(axis.title.x = element_blank(),
legend.position = "none") +
labs(title = "% Currently using e-cigarettes increases &\n% Currently using other products decreases",
subtitle = NULL,
y = "% of students")
title_uw <- ggdraw() +
draw_label(
"Have e-cigarette rates possibly influenced tobacco use?",
fontface = 'bold',
size=14,
x = 0,
hjust = 0
) +
theme(
plot.margin = margin(0, 0, 0, 0)
)
plotsA_uw <- plot_grid(plotA_uw,
rel_widths = c(1,1))
plotsBC_uw <- plot_grid(plotB_uw,
plotC_uw,
rel_widths = c(1,1))
# this will take the legend from plot1c to use as the legend for the plot we are creating
legend_uw <- get_legend(plot1c +
theme(legend.position = "bottom",
legend.direction = "horizontal"))
figure_uw <- plot_grid(title_uw,
plotsA_uw,
plotsBC_uw,
legend_uw,
ncol = 1,
rel_heights = c(0.1,
1,
1,
0.1),
scale = 1.0)
figure_uw

Survey Weighting
It turns out that our analysis thus far has been brushing an important statistical concept under the rug, related to how our data were collected. Our data come from responses to a survey, which may have a particular sampling scheme to capture data about the population we are interested in. For example, the survey may be designed to capture a set of individuals who reflect the characteristics of the population that we are interested in drawing conclusions about. However, only a fraction of the individuals who were contacted about taking the survey may have completed it, and this fraction of individuals may no longer be representative of the population. Or the survey may be designed to over-sample a particular group of interest so that individuals from that group show up more often as survey respondents than are present in the population overall. In order to account for the fact that the survey respondents may not reflect the composition of the population we want to generalize to, we can emply a technique called survey weighting.
Survey weighting is a common technique used in survey data analysis because often the individuals that take a survey are not necessarily representative of the population that we are trying to gather information about. For example, we may have more females that respond to the survey than males because perhaps female students were more willing to participate. In this case, the proportion of data values in our data will be smaller for the males than the proportion of actual male students and larger for the females than the true proportion of actual female students. To get a better estimate of overall e-cigarette smoking rates, the data from the males can be weighted based on the true proportion of male students to amplify the contribution of the responses from the males that did participate. Conversely, the female data can be weighted to diminish the contribution if their responses to the overall picture. We will see if using survey weighting changes the general trends that we see in our data.
Calculating survey weights involves making a weight based on the ratio of the proportion of survey respondents from a particular group and the actual proportion of that group in the population. For example, let’s say that females account for 50% of the population and males account for 50 % of the population. Let’s also say that 75% of the respondents to the survey were female and only 25% were males.
Then we could calculate survey weights using this formula:
\[ \frac{\text{actual proportion of group in the population}}{\text{ proportion of group in the respondents}}\]
Thus the weight for the females would be calculated as:
\[ \frac{.5}{.75} = .67\]
The weight for the males would be calculated as:
\[ \frac{.5}{.25} = 2\]
Therefore each male response value would be multiplied by a factor of 2 and would have twice the contribution, while the female response values would have only about 70% of the contribution that they would have had without weighting.
Note that survey weights are in reality corrected for other aspects - for example the response rate to individual questions.
We do not need to calculate survey weights for our data as they were already supplied in the data set, as described in the codebooks.
srvyr package and survey design
We will now use the srvyr package to evaluate our data using survey weights that were provided in the data for each year, as described in the respective codebooks. This package contains functions that allow the user to easily perform calculations from the data that take the survey design into account, without having to work out the math by hand.
Within the data you will see that we have three variables related to the survey sampling scheme: psu, finwgt, and stratum. Details about these variables are available, for example, in the 2019 Methodology Report.
In brief they represent:
psu: Surveys like the one used to create the data we are using often sample people based on strata. This is done to ensure that the responses are representative of the population of interest. Thus, often people first think about ensuring that surveys are conducted in a variety of geographical areas. This is often called the primary sampling unit or PSU. In this survey, the county where the student’s school was located was used as the PSU.
stratum: A categorical variable that indicates subsets of the data that include respondents from different PSUs. In our case, strata are determined by the predominant minority in the PSU (Non-Hispanic Black or Hispanic), whether the PSU is urban or non-urban, and what percent of the students in the PSU fall into the predominant minority group. PSUs are allocated across the 16 possible strata according to the sampling scheme. These strata values allow estimates based on the survey responses to be calculated using different strata allowing for improved precision of the response estimates.
AVOCADO: I added a bunch of details here to the definition of stratum - perhaps give it a quick read. I also think it might be worth including one of the Methodology Reports, which is where I pulled this information from.
finwgt: The survey weight which was calculated based on a variety of factors.
This link and this link have more information about the study design of the data that we are using.
For detailed information on such survey designs in general see here and here.
We will use the as_survey_design() function of the srvyrpackage to create a survey object with a specified survey design. This is a special R object that includes information about how the survey was conducted that can be taken into account in the analysis.
There are several arguments to pay attention to:
- The
strata argument is used to specify the variable(s) that defined strata in the data. In this case, we will use the stratum variable.
- The
ids argument is used to define cluster ids within the data. In this case we will use the psu variable.
- The
weight argument is the used to define which variable(s) are the survey weights.
- The
nest = TRUE argument, forces cluster ids (in this case the PSU) to be nested within the strata.
We can then use the survey_mean() function to calculate percentages of students who report using tobacco for each year while accounting for the survey design and weights. We will specify that we want confidence interval estimates by using the vartype = "ci" argument. The confidence intervals in our case give a range of possible values for the true population mean based on the data observed in the survey. We will multiply these values by 100 to get percentages. (Note: We could also have calculated confidence intervals for the unweighted results above by computing them by hand; we leave this as a potential exercise.)
Since the survey weights are specific to a single year of the survey results, we need to create survey design objects for each year separately. We will use group_by and group_modify, which is also from the dplyr package, to do this. We first write the function that we want to call on each group.
This function will take an input called currYear, which will be one set of survey responses for a specific year, and then craetes a survey design based on the stratum and finwgt specific to that year. It will then calculate the mean for student respondants who have ever tried any tobacco products or are a current user of any tobacco products accounting for the survey design and weights using survey_mean() as was just described. The function will then wrangle the data to produce new variables about the type of mean estimate that was given from the survey_mean output and the type of user. This
Weighted Sample
# A tibble: 5 x 7
# Groups: year [5]
year tobacco_ever tobacco_ever_low tobacco_ever_upp tobacco_current
<dbl> <dbl> <dbl> <dbl> <dbl>
1 2015 0.372 0.344 0.400 0.180
2 2016 0.338 0.319 0.358 0.148
3 2017 0.307 0.284 0.330 0.139
4 2018 0.339 0.318 0.360 0.185
5 2019 0.408 0.384 0.433 0.233
# … with 2 more variables: tobacco_current_low <dbl>, tobacco_current_upp <dbl>
Now let’s make the function wrangle the output in a more usable form too:
surveyMeanA <- function(currYear){
options(survey.lonely.psu = "average")
currYear %>%
as_survey_design(strata = stratum,
ids = psu,
weight = finwgt,
nest = TRUE) %>%
summarize(tobacco_ever = survey_mean(tobacco_ever,
vartype = "ci",
na.rm = TRUE),
tobacco_current = survey_mean(tobacco_current,
vartype = "ci",
na.rm = TRUE)) %>%
mutate_all( "*", 100) %>%
pivot_longer(everything(),
names_to = "Type",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(str_detect(Type,"_low") ~ "Lower",
grepl("_upp", Type) ~ "Upper",
TRUE ~ "Mean"),
User = case_when(grepl("ever", Type) ~ "Ever",
grepl("current", Type) ~ "Current",
TRUE ~ "Mean"))
}
nyts_data %>%
group_by(year) %>%
group_modify(~surveyMeanA(.x))
# A tibble: 30 x 5
# Groups: year [5]
year Type `Percentage of students` Estimate User
<dbl> <chr> <dbl> <chr> <chr>
1 2015 tobacco_ever 37.2 Mean Ever
2 2015 tobacco_ever_low 34.4 Lower Ever
3 2015 tobacco_ever_upp 40.0 Upper Ever
4 2015 tobacco_current 18.0 Mean Current
5 2015 tobacco_current_low 16.2 Lower Current
6 2015 tobacco_current_upp 19.9 Upper Current
7 2016 tobacco_ever 33.8 Mean Ever
8 2016 tobacco_ever_low 31.9 Lower Ever
9 2016 tobacco_ever_upp 35.8 Upper Ever
10 2016 tobacco_current 14.8 Mean Current
# … with 20 more rows
### AVOCADO: Remove rest of chunk from here if you are OK with this way of doing it
nyts_data %>%
as_survey_design(strata = stratum,
ids = psu,
weight = finwgt,
nest = TRUE) %>%
group_by(year) %>%
summarize(tobacco_ever = survey_mean(tobacco_ever,
vartype = "ci",
na.rm = TRUE),
tobacco_current = survey_mean(tobacco_current,
vartype = "ci",
na.rm = TRUE)) %>%
mutate_at(vars(-year), "*", 100) %>%
pivot_longer(cols = -year,
names_to = "Type",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(grepl("_low", Type) ~ "Lower",
grepl("_upp", Type) ~ "Upper",
TRUE ~ "Mean"),
User = case_when(grepl("ever", Type) ~ "Ever",
grepl("current", Type) ~ "Current",
TRUE ~ "Mean")) %>%
head()
# A tibble: 6 x 5
year Type `Percentage of students` Estimate User
<dbl> <chr> <dbl> <chr> <chr>
1 2015 tobacco_ever 37.2 Mean Ever
2 2015 tobacco_ever_low 34.4 Lower Ever
3 2015 tobacco_ever_upp 40.0 Upper Ever
4 2015 tobacco_current 18.0 Mean Current
5 2015 tobacco_current_low 16.2 Lower Current
6 2015 tobacco_current_upp 19.8 Upper Current
We will now make a plot using this data. The confidence intervals are included using the geom_linerange() function of the ggplot2 package.
### AVOCADO: Remove this first version of the figure if you are OK with my modifications below
plotA_w <- nyts_data %>%
as_survey_design(strata = stratum,
ids = psu,
weight = finwgt,
nest = TRUE) %>%
group_by(year) %>%
summarize(tobacco_ever = survey_mean(tobacco_ever,
vartype = "ci",
na.rm = TRUE),
tobacco_current = survey_mean(tobacco_current,
vartype = "ci",
na.rm = TRUE)) %>%
mutate_at(vars(-year), "*", 100) %>%
pivot_longer(cols = -year,
names_to = "Type",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(grepl("_low", Type) ~ "Lower",
grepl("_upp", Type) ~ "Upper",
TRUE ~ "Mean"),
User = case_when(grepl("ever", Type) ~ "Ever",
grepl("current", Type) ~ "Current",
TRUE ~ "Mean")) %>%
dplyr::select(-Type) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`) %>%
ggplot(aes(x=year,y=Mean)) +
geom_line(aes(linetype=User)) +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1, show.legend = FALSE) +
scale_linetype_manual(values = c(2,1)) +
scale_color_manual(values = v_colors) +
scale_y_continuous(breaks = seq(0,70,by=10),
labels = seq(0,70,by=10),
limits = c(0,70)) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "Tobacco product users more prevalent after 2017",
y = "% of students")
plotA_w

## AVOCADO: updated version using group_modify
plotA_w <- nyts_data %>%
group_by(year) %>%
group_modify(~surveyMeanA(.x)) %>%
dplyr::select(-Type) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`) %>%
ggplot(aes(x=year,y=Mean)) +
geom_line(aes(linetype=User)) +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1, show.legend = FALSE) +
scale_linetype_manual(values = c(2,1)) +
scale_color_manual(values = v_colors) +
scale_y_continuous(breaks = seq(0,70,by=10),
labels = seq(0,70,by=10),
limits = c(0,70)) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "Tobacco product users more prevalent after 2017",
y = "% of students")
plotA_w

Now we can see that we have confidence interval ranges plotted for each value.
We will make a similar plot for students who reported ever trying or who currently use e-cigarettes as opposed to tobacco in general.
surveyMeanB <- function(currYear){
options(survey.lonely.psu = "average")
currYear %>%
as_survey_design(strata = stratum,
ids = psu,
weight = finwgt,
nest = TRUE) %>%
summarize(ecig_ever_year = survey_mean(ecig_ever, vartype = "ci", na.rm=TRUE),
non_ecig_ever_year = survey_mean(non_ecig_ever, vartype = "ci", na.rm=TRUE)) %>%
mutate_all("*", 100) %>%
pivot_longer(everything(),
names_to = "Category",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(grepl("_low", Category) ~ "Lower",
grepl("_upp", Category) ~ "Upper",
TRUE ~ "Mean"),
User = case_when(grepl("ever", Category) ~ "Ever",
grepl("current", Category) ~ "Current"),
Product = case_when(grepl("non_ecig", Category) ~ "Other products",
TRUE ~ "E-cigarettes")) %>%
dplyr::select(-Category) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`)
}
nyts_data %>%
group_by(year) %>%
group_modify(~surveyMeanB(.x)) %>%
head()
# A tibble: 6 x 6
# Groups: year [3]
year User Product Mean Lower Upper
<dbl> <chr> <chr> <dbl> <dbl> <dbl>
1 2015 Ever E-cigarettes 26.6 24.3 29.0
2 2015 Ever Other products 31.3 28.7 33.8
3 2016 Ever E-cigarettes 22.6 21.0 24.3
4 2016 Ever Other products 28.2 26.2 30.2
5 2017 Ever E-cigarettes 21.1 19.1 23.2
6 2017 Ever Other products 24.3 22.2 26.4
## AVOCADO: Drop this version of code
nyts_data %>%
as_survey_design(strata = stratum, ids = psu, weight = finwgt, nest=TRUE) %>%
group_by(year) %>%
summarize(ecig_ever_year = survey_mean(ecig_ever, vartype = "ci", na.rm=TRUE),
non_ecig_ever_year = survey_mean(non_ecig_ever, vartype = "ci", na.rm=TRUE)) %>% mutate_at(vars(-year), "*", 100) %>%
pivot_longer(cols = -year,
names_to = "Category",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(grepl("_low", Category) ~ "Lower",
grepl("_upp", Category) ~ "Upper",
TRUE ~ "Mean"),
User = case_when(grepl("ever", Category) ~ "Ever",
grepl("current", Category) ~ "Current"),
Product = case_when(grepl("non_ecig", Category) ~ "Other products",
TRUE ~ "E-cigarettes")) %>%
dplyr::select(-Category) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`) %>%
head()
# A tibble: 6 x 6
year User Product Mean Lower Upper
<dbl> <chr> <chr> <dbl> <dbl> <dbl>
1 2015 Ever E-cigarettes 26.6 24.4 28.9
2 2015 Ever Other products 31.3 28.6 33.9
3 2016 Ever E-cigarettes 22.6 20.9 24.3
4 2016 Ever Other products 28.2 26.1 30.3
5 2017 Ever E-cigarettes 21.1 19.1 23.1
6 2017 Ever Other products 24.3 22.1 26.5
## AVOCADO: Drop this version of plot
plotB_w <- nyts_data %>%
as_survey_design(strata = stratum, ids = psu, weight = finwgt, nest=TRUE) %>%
group_by(year) %>%
summarize(ecig_ever_year = survey_mean(ecig_ever, vartype = "ci", na.rm=TRUE),
non_ecig_ever_year = survey_mean(non_ecig_ever, vartype = "ci", na.rm=TRUE)) %>% mutate_at(vars(-year), "*", 100) %>%
pivot_longer(cols = -year,
names_to = "Category",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(grepl("_low", Category) ~ "Lower",
grepl("_upp", Category) ~ "Upper",
TRUE ~ "Mean"),
User = case_when(grepl("ever", Category) ~ "Ever",
grepl("current", Category) ~ "Current"),
Product = case_when(grepl("non_ecig", Category) ~ "Other products",
TRUE ~ "E-cigarettes")) %>%
dplyr::select(-Category) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`) %>%
ggplot(aes(x=year,y=Mean, color = Product)) +
geom_line() +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1, show.legend = FALSE) +
scale_linetype_manual(values = c(2,1)) +
scale_color_manual(values = v_colors) +
scale_y_continuous(breaks = seq(0,60,by=10),
labels = seq(0,60,by=10),
limits = c(0,60)) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "% Ever trying e-cigarettes increases &\n% Ever trying other products decreases",
y = "% of students")
plotB_w

plotB_w <- nyts_data %>%
group_by(year) %>%
group_modify(~surveyMeanB(.x)) %>%
ggplot(aes(x=year,y=Mean, color = Product)) +
geom_line() +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1, show.legend = FALSE) +
scale_linetype_manual(values = c(2,1)) +
scale_color_manual(values = v_colors) +
scale_y_continuous(breaks = seq(0,60,by=10),
labels = seq(0,60,by=10),
limits = c(0,60)) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "% Ever trying e-cigarettes increases &\n% Ever trying other products decreases",
y = "% of students")
plotB_w

Now we will do the same but for current users:
surveyMeanC <- function(currYear){
options(survey.lonely.psu = "average")
currYear %>%
as_survey_design(strata = stratum,
ids = psu,
weight = finwgt,
nest = TRUE) %>%
summarize(ecig_current_year = survey_mean(ecig_current, vartype = "ci", na.rm=TRUE),
non_ecig_current_year = survey_mean(non_ecig_current, vartype = "ci", na.rm=TRUE)) %>%
mutate_all("*", 100) %>%
pivot_longer(everything(),
names_to = "Category",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(grepl("_low", Category) ~ "Lower",
grepl("_upp", Category) ~ "Upper",
TRUE ~ "Mean"),
User = case_when(grepl("ever", Category) ~ "Ever",
grepl("current", Category) ~ "Current"),
Product = case_when(grepl("non_ecig", Category) ~ "Other products",
TRUE ~ "E-cigarettes")) %>%
dplyr::select(-Category) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`)
}
#AVOCADO: Drop this version of plot code
plotC_w <- nyts_data %>%
as_survey_design(strata = stratum, ids = psu, weight = finwgt, nest=TRUE) %>%
group_by(year) %>%
summarize(ecig_current_year = survey_mean(ecig_current, vartype = "ci", na.rm=TRUE),
non_ecig_current_year = survey_mean(non_ecig_current, vartype = "ci", na.rm=TRUE)) %>%
mutate_at(vars(-year), "*", 100) %>%
pivot_longer(cols = -year,
names_to = "Category",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(grepl("_low", Category) ~ "Lower",
grepl("_upp", Category) ~ "Upper",
TRUE ~ "Mean"),
User = case_when(grepl("ever", Category) ~ "Ever",
grepl("current", Category) ~ "Current"),
Product = case_when(grepl("non_ecig", Category) ~ "Other products",
TRUE ~ "E-cigarettes")) %>%
dplyr::select(-Category) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`) %>%
ggplot(aes(x=year,y=Mean, color=Product)) +
geom_line(aes(linetype="dashed")) +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1, show.legend = FALSE) +
scale_linetype_manual(values = c(2,1)) +
scale_y_continuous(breaks = seq(0, 60, by = 10), limits = c(0,60)) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "% Currently using e-cigarettes increases &\n% Currently using other products decreases",
y = "% of students")
plotC_w

plotC_w <- nyts_data %>%
group_by(year) %>%
group_modify(~surveyMeanC(.x)) %>%
ggplot(aes(x=year,y=Mean, color=Product)) +
geom_line(aes(linetype="dashed")) +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1, show.legend = FALSE) +
scale_linetype_manual(values = c(2,1)) +
scale_y_continuous(breaks = seq(0, 60, by = 10), limits = c(0,60)) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "% Currently using e-cigarettes increases &\n% Currently using other products decreases",
y = "% of students")
plotC_w

Now we will put these plots together again using the cowplot package:
title_w <- ggdraw() +
draw_label(
expression("What is the relationship between vaping rates and tobacco use?"),
fontface = 'bold',
size=14,
x = 0,
hjust = 0
) +
theme(
plot.margin = margin(0, 0, 0, 0)
)
plotsA_w <- plot_grid(plotA_w,
rel_widths = c(1),
align = "v",
axis = "bt")
plotsBC_w <- plot_grid(plotB_w,
plotC_w,
rel_widths = c(1,1),
align = "v",
axis = "bt")
legend_w <- get_legend(plot1c +
theme(legend.position = "bottom",
legend.direction = "horizontal"))
figure_w <- plot_grid(title_w,
plotsA_w,
plotsBC_w,
legend_w,
ncol = 1,
rel_heights = c(0.1,
1,
1,
0.1),
scale = 1.0)
figure_w

We can see that these figures look quite similar to the ones generated without using the survey weights.
Artificial Cohort
Although the survey design does not allow specific individuals to be followed over time, we will use certain subsets of the data from each year to construct an artificial cohort where we follow students of the same age group as they get older. This will allow us to look at how tobacco usage changed for students who were in 8th grade in 2015 as they aged.
All of the data so far has included all 6th-12th graders every year. Now we will look at just the data for students expected to graduate in 2019. These are the students who were in 8th grade in 2015, most of whom were 9th graders in 2016, 10th graders in 2017 and so on. We will filter the data to just the students expected to be in the graduating class of 2019.
surveyMeanCohort <- function(currYear){
options(survey.lonely.psu = "average")
currYear %>%
as_survey_design(strata = stratum,
ids = psu,
weight = finwgt,
nest = TRUE) %>%
summarize(ecig_ever_year = survey_mean(ecig_ever, vartype = "ci", na.rm=TRUE),
ecig_current_year = survey_mean(ecig_current, vartype = "ci", na.rm=TRUE),
non_ecig_ever_year = survey_mean(non_ecig_ever, vartype = "ci", na.rm=TRUE),
non_ecig_current_year = survey_mean(non_ecig_current, vartype = "ci", na.rm=TRUE),
tobacco_ever_year = survey_mean(tobacco_ever, vartype = "ci", na.rm=TRUE),
tobacco_current_year = survey_mean(tobacco_current, vartype = "ci", na.rm=TRUE))%>%
mutate_all("*", 100) %>%
pivot_longer(everything(),
names_to = "Category",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(grepl("_low", Category) ~ "Lower",
grepl("_upp", Category) ~ "Upper",
TRUE ~ "Mean"),
User = case_when(grepl("ever", Category) ~ "Ever",
grepl("current", Category) ~ "Current"),
Product = case_when(grepl("non_ecig", Category) ~ "Other products",
grepl("tobacco", Category) ~ "Any tobacco product",
TRUE ~ "E-cigarettes")) %>%
dplyr::select(-Category) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`)
}
Cohort_data <-nyts_data %>%
filter((Grade == "8" & year == 2015) |
(Grade == "9" & year == 2016) |
(Grade == "10" & year == 2017) |
(Grade == "11" & year == 2018) |
(Grade == "12" & year == 2019)
) %>%
as_survey_design(strata = stratum, ids = psu, weight = finwgt) %>%
group_by(year) %>%
summarize(ecig_ever_year = survey_mean(ecig_ever, vartype = "ci", na.rm=TRUE),
ecig_current_year = survey_mean(ecig_current, vartype = "ci", na.rm=TRUE),
non_ecig_ever_year = survey_mean(non_ecig_ever, vartype = "ci", na.rm=TRUE),
non_ecig_current_year = survey_mean(non_ecig_current, vartype = "ci", na.rm=TRUE),
tobacco_ever_year = survey_mean(tobacco_ever, vartype = "ci", na.rm=TRUE),
tobacco_current_year = survey_mean(tobacco_current, vartype = "ci", na.rm=TRUE))%>%
mutate_at(vars(-year), "*", 100) %>%
pivot_longer(cols = -year, names_to = "Category", values_to = "Percentage of students")%>%
mutate(Estimate = case_when(grepl("_low", Category) ~ "Lower",
grepl("_upp", Category) ~ "Upper",
TRUE ~ "Mean"),
User = case_when(grepl("ever", Category) ~ "Ever",
grepl("current", Category) ~ "Current"),
Product = case_when(grepl("non_ecig", Category) ~ "Other products",
grepl("tobacco", Category) ~ "Any tobacco product",
TRUE ~ "E-cigarettes")) %>%
dplyr::select(-Category) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`)
head(Cohort_data)
# A tibble: 6 x 6
year User Product Mean Lower Upper
<dbl> <chr> <chr> <dbl> <dbl> <dbl>
1 2015 Ever E-cigarettes 20.1 17.1 23.0
2 2015 Current E-cigarettes 8.12 6.72 9.52
3 2015 Ever Other products 20.7 17.9 23.6
4 2015 Current Other products 7.06 5.66 8.45
5 2015 Ever Any tobacco product 26.9 23.5 30.3
6 2015 Current Any tobacco product 10.9 9.11 12.6
# A tibble: 6 x 6
# Groups: year [1]
year User Product Mean Lower Upper
<dbl> <chr> <chr> <dbl> <dbl> <dbl>
1 2015 Ever E-cigarettes 20.1 16.8 23.3
2 2015 Current E-cigarettes 8.12 6.65 9.59
3 2015 Ever Other products 20.7 17.5 23.9
4 2015 Current Other products 7.06 5.53 8.58
5 2015 Ever Any tobacco product 26.9 23.1 30.7
6 2015 Current Any tobacco product 10.9 9.01 12.7
We will now make similar plots to those above for this subset of the data:
plotA_w_8 <-Cohort_data %>%
filter(Product == "Any tobacco product") %>%
ggplot(aes(x=year,y=Mean)) +
geom_line(aes(linetype=User)) +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1) +
scale_linetype_manual(values = c(2,1)) +
scale_y_continuous(breaks = seq(0,70,by=10),
labels = seq(0,70,by=10),
limits = c(0,70)) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "Tobacco product use became increasingly prevalent",
y = "% of students")
plotB_w_8 <-Cohort_data %>%
filter(Product != "Any tobacco product", User == "Ever") %>%
ggplot(aes(x=year,y=Mean, color=Product)) +
geom_line(linetype=1) +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1) +
scale_y_continuous(breaks = seq(10, 60, by = 10), limits = c(10,60)) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "% ever trying tobacco products increases",
y = "% of students")
plotC_w_8 <-Cohort_data %>%
filter(Product != "Any tobacco product", User == "Current") %>%
ggplot(aes(x=year,y=Mean, color=Product)) +
geom_line(aes(linetype=User)) +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1) +
scale_linetype_manual(values = c(2,1)) +
scale_y_continuous(breaks = seq(0, 60, by = 10), limits = c(0,60)) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "E-cigarette use surpasses use of other products",
y = "% of students")
title_w_8 <- ggdraw() +
draw_label(
expression("Among students expected to be in the graduating class of 2019, how are vaping rates related to tobacco use?"),
fontface = 'bold',
size=14,
x = 0,
hjust = 0
) +
theme(
plot.margin = margin(0, 0, 0, 0)
)
plotsA_w_8 <- plot_grid(plotA_w_8,
rel_widths = c(1),
align = "v",
axis = "bt")
plotsBC_w_8 <- plot_grid(plotB_w_8,
plotC_w_8,
rel_widths = c(1,1),
axis = "bt")
legend_w_8 <- get_legend(plot1c +
theme(legend.position = "bottom",
legend.direction = "horizontal"))
figure_w_8 <- plot_grid(title_w_8,
plotsA_w_8,
plotsBC_w_8,
legend_w_8,
ncol = 1,
rel_heights = c(0.1,
1,
1,
0.1),
scale = 1.0
)
figure_w_8

LS0tCnRpdGxlOiAiT3BlbiBDYXNlIFN0dWRpZXMgOiBWYXBpbmcgQmVoYXZpb3JzIGluIEFtZXJpY2FuIFlvdXRoIgphdXRob3I6ICJNaWNoYWVsIE9udGl2ZXJvcywgQ2FycmllIFdyaWdodCwgUGhELiAiCgpjc3M6IHN0eWxlLmNzcwpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHNlbGZfY29udGFpbmVkOiB5ZXMKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgbnVtYmVyX3NlY3Rpb25zOiBubwogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwoKLS0tCjxzdHlsZT4KI1RPQyB7CiAgYmFja2dyb3VuZDogdXJsKCJodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vaW1nL2xvZ28uanBnIik7CiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluOwogIHBhZGRpbmctdG9wOiAyNDBweCAhaW1wb3J0YW50OwogIGJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQ7Cn0KPC9zdHlsZT4KCmBgYHtyLCBlY2hvPUZBTFNFfQprbml0X3RpbWVfc3RhcnQgPC0gU3lzLnRpbWUoKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTgsIGRwaT0zMDApIApgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoaW5jbHVkZSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgZWNobyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgY2FjaGUgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBvdXQud2lkdGggPSAnOTAlJykKbGlicmFyeShoZXJlKQpsaWJyYXJ5KGtuaXRyKQpgYGAKCgojIyMjIHsub3V0bGluZSB9CmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI4MDAgcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiZmluYWxfcGxvdC5wbmciKSkKYGBgCiMjIyMKCgoKCiMjIHsuZGlzY2xhaW1lcl9ibG9ja30KCioqRGlzY2xhaW1lcioqOiBUaGUgcHVycG9zZSBvZiB0aGUgW09wZW4gQ2FzZSBTdHVkaWVzXShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8pe3RhcmdldD0iX2JsYW5rIn0gcHJvamVjdCBpcyAqKnRvIGRlbW9uc3RyYXRlIHRoZSB1c2Ugb2YgdmFyaW91cyBkYXRhIHNjaWVuY2UgbWV0aG9kcywgdG9vbHMsIGFuZCBzb2Z0d2FyZSBpbiB0aGUgY29udGV4dCBvZiBtZXNzeSwgcmVhbC13b3JsZCBkYXRhKiouIEEgZ2l2ZW4gY2FzZSBzdHVkeSBkb2VzIG5vdCBjb3ZlciBhbGwgYXNwZWN0cyBvZiB0aGUgcmVzZWFyY2ggcHJvY2VzcywgaXMgbm90IGNsYWltaW5nIHRvIGJlIHRoZSBtb3N0IGFwcHJvcHJpYXRlIHdheSB0byBhbmFseXplIGEgZ2l2ZW4gZGF0YSBzZXQsIGFuZCBzaG91bGQgbm90IGJlIHVzZWQgaW4gdGhlIGNvbnRleHQgb2YgbWFraW5nIHBvbGljeSBkZWNpc2lvbnMgd2l0aG91dCBleHRlcm5hbCBjb25zdWx0YXRpb24gZnJvbSBzY2llbnRpZmljIGV4cGVydHMuIAoKIyMgKipNb3RpdmF0aW9uKioKKioqIApBY2NvcmRpbmcgdG8gYSByZWNlbnQgW3JlcG9ydF0oaHR0cHM6Ly93d3cuY2RjLmdvdi9tbXdyL3ZvbHVtZXMvNjgvd3IvbW02ODA2ZTEuaHRtP3NfY2lkPW1tNjgwNmUxX3cpe3RhcmdldD0iX2JsYW5rIn0sIG92ZXJhbGwgdG9iYWNjbyB1c2UgKippbmNyZWFzZWQqKiBpbiB5b3V0aHMgKG1pZGRsZSBzY2hvb2wgYW5kIGhpZ2ggc2Nob29sIHN0dWRlbnRzKSBpbiB0aGUgVW5pdGVkIFN0YXRlcyBpbiAyMDE3IGFuZCAyMDE4LCBkZXNwaXRlIHByZXZpb3VzIHllYXJzIG9mIGRlY2xpbmluZyB1c2UuCgpUaGlzIG1ham9yIGluY3JlYXNlIGlzIGF0dHJpYnV0ZWQgdG8gYW4gaW5jcmVhc2UgaW4gdGhlIHVzZSBvZiBlbGVjdHJvbmljIGNpZ2FyZXR0ZSAoZS1jaWdhcmV0dGUpIHByb2R1Y3RzLgoKRS1jaWdhcmV0dGVzIGFyZSByZWZlcnJlZCB0byBieSBtYW55IGRpZmZlcmVudCBuYW1lcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bzoKCjEpIEVsZWN0cm9uaWMgbmljb3RpbmUgZGVsaXZlcnkgc3lzdGVtcyAoRU5EUykKMikgVmFwZXMKMykgZS1ob29rYWhzCjQpIHZhcGUgcGVucwo1KSB0YW5rcwo2KSBtb2RzCgpUaGUgZGV2aWNlcyB2YXJ5IGdyZWF0bHk6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIifQoKaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly93d3cubHVuZy5vcmcvZ2V0bWVkaWEvOGFjOGFiOGMtZTdmYy00OTdiLTgzODQtNDQxNjE1ZjUwZmYwL2VjaWdzX0suanBnLmpwZyIpCmBgYAoKIyMjIyMgW1tzb3VyY2VdKGh0dHBzOi8vd3d3Lmx1bmcub3JnL3F1aXQtc21va2luZy9lLWNpZ2FyZXR0ZXMtdmFwaW5nL2x1bmctaGVhbHRoKV0KClNlZSB0aGlzIFtDREMgZ3VpZGVdKGh0dHBzOi8vd3d3LmNkYy5nb3YvdG9iYWNjby9iYXNpY19pbmZvcm1hdGlvbi9lLWNpZ2FyZXR0ZXMvcGRmcy9lY2lnYXJldHRlLW9yLXZhcGluZy1wcm9kdWN0cy12aXN1YWwtZGljdGlvbmFyeS01MDgucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCB0aGUgW0FtZXJpY2FuIEx1bmcgQXNzb2NpYXRpb24gd2Vic2l0ZV0oaHR0cHM6Ly93d3cubHVuZy5vcmcvcXVpdC1zbW9raW5nL2UtY2lnYXJldHRlcy12YXBpbmcvbHVuZy1oZWFsdGgpe3RhcmdldD0iX2JsYW5rIn0gZm9yIG1vcmUgaW5mb3JtYXRpb24uIAoKVGhlIHJlcG9ydCBmb3VuZCB0aGF0OgoKPiBEdXJpbmcgMjAxN+KAkzIwMTgsIGN1cnJlbnQgdXNlIG9mIGFueSB0b2JhY2NvIHByb2R1Y3QgKippbmNyZWFzZWQgMzguMyUqKiAoZnJvbSAxOS42JSB0byAyNy4xJSkgYW1vbmcgaGlnaCBzY2hvb2wgc3R1ZGVudHMgYW5kICoqMjguNiUqKiAoZnJvbSA1LjYlIHRvIDcuMiUpIGFtb25nIG1pZGRsZSBzY2hvb2wgc3R1ZGVudHM7IGUtY2lnYXJldHRlIHVzZSAqKmluY3JlYXNlZCA3Ny44JSoqIChmcm9tIDExLjclIHRvIDIwLjglKSBhbW9uZyBoaWdoIHNjaG9vbCBzdHVkZW50cyBhbmQgKio0OC41JSoqIChmcm9tIDMuMyUgdG8gNC45JSkgYW1vbmcgbWlkZGxlIHNjaG9vbCBzdHVkZW50cy4KCgpJbiAyMDE4LCB0aGUgW0ZlZGVyYWwgRHJ1ZyBBZG1pbmlzdHJhdGlvbiAoRkRBKSBpbiB0aGUgVW5pdGVkIFN0YXRlc10oaHR0cHM6Ly9hY3Nqb3VybmFscy5vbmxpbmVsaWJyYXJ5LndpbGV5LmNvbS9kb2kvZnVsbC8xMC4xMDAyL2NuY3IuMzE4Njgpe3RhcmdldD0iX2JsYW5rIn0gc3RhdGVkIHRoYXQgZS1jaWdhcmV0dGUgdXNhZ2UgdXNlIGFtb25nIHlvdXRoIHJlYWNoZWQ6ICAKCj4g4oCcbm90aGluZyBzaG9ydCBvZiBhbiAqKmVwaWRlbWljIHByb3BvcnRpb24gb2YgZ3Jvd3RoKirigJ0KCgpJbiB0aGlzIGNhc2Ugc3R1ZHksIHdlIHdpbGwgYmUgaW52ZXN0aWdhdGluZyB0aGUgc2FtZSBkYXRhIHVzZWQgaW4gdGhlIHJlcG9ydCB0aGF0IGdlbmVyYXRlZCB0aGUgYWJvdmUgZmluZGluZ3MuIFRoaXMgZGF0YSBjb21lcyBmcm9tIHRoZSBbVGhlIE5hdGlvbmFsIFlvdXRoIFRvYmFjY28gU3VydmV5IChOWVRTKV0oaHR0cHM6Ly93d3cuY2RjLmdvdi90b2JhY2NvL2RhdGFfc3RhdGlzdGljcy9zdXJ2ZXlzL255dHMvaW5kZXguaHRtKXt0YXJnZXQ9Il9ibGFuayJ9LgoKIyMjIyB7LnJlZmVyZW5jZV9ibG9ja30KCkdlbnR6a2UsIEFuZHJlYSBTLiwgTWVsaXNhIENyZWFtZXIsIEthcmVuIEEuIEN1bGxlbiwgQnJpZGdldCBLLiBBbWJyb3NlLCBHb3Jkb24gV2lsbGlzLCBBaG1lZCBKYW1hbCwgYW5kIEJyaWFuIEEuIEtpbmcuICDigJxWaXRhbCBTaWduczogVG9iYWNjbyBQcm9kdWN0IFVzZSBBbW9uZyBNaWRkbGUgYW5kIEhpZ2ggU2Nob29sIFN0dWRlbnRzIC0gVW5pdGVkIFN0YXRlcywgMjAxMS0yMDE4LuKAnSAqKk1NV1IuIE1vcmJpZGl0eSBhbmQgTW9ydGFsaXR5IFdlZWtseSBSZXBvcnQqKiA2OCAoNik6IDE1N+KAkzY0ICgyMDE5KS4KCiMjIyMKCgojIyAqKk1haW4gUXVlc3Rpb25zKioKKioqIAoKIyMjIyB7Lm1haW5fcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBPdXIgbWFpbiBxdWVzdGlvbjogPC91PjwvYj4KCjEpIEhvdyBoYXMgdG9iYWNjbyBhbmQgZS1jaWdhcmV0dGUvdmFwaW5nIHVzZSBieSBBbWVyaWNhbiB5b3V0aHMgY2hhbmdlZCBzaW5jZSAyMDE1PwoyKSBIb3cgZG8gdmFwaW5nIHJhdGVzIGNvbXBhcmUgYmV0d2VlbiBtYWxlcyBhbmQgZmVtYWxlcz8KMykgV2hhdCB2YXBpbmcgYnJhbmRzIGFuZCBmbGF2b3JzIGFwcGVhciB0byBiZSB1c2VkIHRoZSBtb3N0IGZyZXF1ZW50bHk/ICAKV2Ugd2lsbCBiYXNlIHRoaXMgb24gdGhlIGZvbGxvd2luZyBzdXJ2ZXkgcXVlc3Rpb25zOiAgIAo+ICJEdXJpbmcgdGhlIHBhc3QgMzAgZGF5cywgd2hhdCBicmFuZCBvZiBlLWNpZ2FyZXR0ZXMgZGlkIHlvdSB1c3VhbGx5IHVzZT8iICAgCj4iIFdoYXQgZmxhdm9ycyBvZiB0b2JhY2NvIHByb2R1Y3RzIGhhdmUgeW91IHVzZWQgaW4gdGhlIHBhc3QKMzAgZGF5cz8iIAoKNCkgSXMgdGhlcmUgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiBlLWNpZ2FyZXR0ZS92YXBpbmcgdXNlIGFuZCBvdGhlciB0b2JhY2NvIHVzZT8KCiMjIyMKCkFWT0NBRE86IE5vdGUgdGhhdCBJIGRpZCBjaGFuZ2UgcXVlc3Rpb24gNCBhYm92ZSB0byBiZSBsZXNzIGNhdXNhbCBzb3VuZGluZwoKIyMgKipMZWFybmluZyBPYmplY3RpdmVzKiogCioqKiAKCkluIHRoaXMgY2FzZSBzdHVkeSwgd2Ugd2lsbCBjb3ZlciBob3cgdG8gaW1wb3J0IGRhdGEgZnJvbSBtdWx0aXBsZSBmaWxlcyBlZmZpY2llbnRseSwgaG93IHRvIGltcG9ydCBkYXRhIGZyb20gZXhjZWwgZmlsZXMsIGFuZCBob3cgdG8gbWFrZSBhIHZhcmlldHkgb2YgdmlzdWFsaXphdGlvbnMgdG8gY29tcGFyZSBtdWx0aXBsZSBncm91cHMgYWNyb3NzIHRpbWUuIFdlIHdpbGwgYWxzbyBkZW1vbnN0cmF0ZSBob3cgdG8gd29yayB3aXRoIGNvZGVib29rcy4gV2Ugd2lsbCBjb3ZlciB0aGUgY29uY2VwdCBvZiBzdXJ2ZXkgd2VpZ2h0aW5nIGFuZCBpbnRyb2R1Y2UgdGhlIGBzcnZ5cmAgcGFja2FnZS4gV2Ugd2lsbCBkaXNjdXNzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gcG9vbGVkIGNyb3NzLXNlY3Rpb25hbCBkYXRhIGFuZCBwYW5lbCBkYXRhLiBXZSB3aWxsIGVzcGVjaWFsbHkgZm9jdXMgb24gdXNpbmcgcGFja2FnZXMgYW5kIGZ1bmN0aW9ucyBmcm9tIHRoZSBbYFRpZHl2ZXJzZWBdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciB3cmFuZ2xpbmcgZGF0YSwgc3VjaCBhcyBgdGlkeXJgIGFuZCBgZHBseXJgIGFuZCBmb3IgdmlzdWFsaXphdGlvbiwgc3VjaCBhcyBhcyBgZ2dwbG90MmAuIFRoZSB0aWR5dmVyc2UgaXMgYSBsaWJyYXJ5IG9mIHBhY2thZ2VzIGNyZWF0ZWQgYnkgUlN0dWRpby4gV2hpbGUgc29tZSBzdHVkZW50cyBtYXkgYmUgZmFtaWxpYXIgd2l0aCBwcmV2aW91cyBSIHByb2dyYW1taW5nIHBhY2thZ2VzLCB0aGVzZSBwYWNrYWdlcyBtYWtlIGRhdGEgc2NpZW5jZSBpbiBSIGVzcGVjaWFsbHkgZWZmaWNpZW50LgoKCkFWT0NBRE86IEkgd291bGQgbGlrZSB0aGVzZSB0byBiZSBtb3JlIGRldGFpbGVkIGFuZCBwcm9iYWJseSBzZXBhcmF0ZWQgaW50byB0d28gY2F0ZWdvcmllcyBhbG9uZyB0aGUgbGluZXMgb2YgZGF0YSBzY2llbmNlIHNraWxscyBhbmQgc3RhdGlzdGljYWwgbWV0aG9kcywgc28gdGhhdCB0aGUgZGF0YSBpbXBvcnQgYW5kIHZpc3VhbGl6YXRpb24gYXJlIGluIG9uZSBjYXRlZ29yeSBhbmQgdGhlIHN1cnZleSB3ZWlnaHRpbmcgaXMgaW4gYW5vdGhlciBjYXRlZ29yeS4gVGhpcyBpcyB0byBoZWxwIGluc3RydWN0b3JzIHdobyBtYXkgYmUgbG9va2luZyBmb3IgYW4gaWxsdXN0cmF0aW9uIG9mIGEgcGFydGljdWxhciB0b29sIG9yIG1ldGhvZCB0byBtb3JlIHJlYWRpbHkgaWRlbnRpZnkgYW4gYXBwcm9wcmlhdGUgY2FzZSBzdHVkeS4gTW9yZSBsaWtlIGtleXdvcmRzLi4uLi4gQW4gYXR0ZW1wdCBpcyBiZWxvdy4KCkRhdGEgc2NpZW5jZSBza2lsbHM6CgoxLiBJbXBvcnQgZGF0YSBmcm9tIEV4Y2VsIGZpbGVzCjIuIE1lcmdlIGRhdGEgZnJvbSBtdWx0aXBsZSBzaW1pbGFyIGJ1dCBub3QgaWRlbnRpY2FsIGRhdGEgc3RydWN0dXJlcwozLiBDcmVhdGUgZWZmZWN0aXZlIGxvbmdpdHVkaW5hbCBkYXRhIHZpc3VhbGl6YXRpb25zCgpTdGF0aXN0aWNhbCBtZXRob2RzOgoKMS4gU3VydmV5IHdlaWdodGluZwoKCmBgYHtyLCBvdXQud2lkdGggPSAiMjAlIiwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIifQoKaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly90aWR5dmVyc2UudGlkeXZlcnNlLm9yZy9sb2dvLnBuZyIpCmBgYAoKCioqKiAKCgpXZSB3aWxsIGJlZ2luIGJ5IGxvYWRpbmcgdGhlIHBhY2thZ2VzIHRoYXQgd2Ugd2lsbCBuZWVkOgoKYGBge3J9CmxpYnJhcnkoaGVyZSkKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShwdXJycikKbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKbGlicmFyeSh0aWR5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkobmFuaWFyKQpsaWJyYXJ5KHNydnlyKQpsaWJyYXJ5KGNvd3Bsb3QpCmBgYAoKIFBhY2thZ2UgICB8IFVzZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQpbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgIHwgdG8gZWFzaWx5IGxvYWQgYW5kIHNhdmUgZGF0YSAgCltyZWFkeGxdKGh0dHBzOi8vcmVhZHhsLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBpbXBvcnQgdGhlIGRhdGEgaW4gdGhlIGV4Y2VsIGZpbGVzIApbbWFncml0dHJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdyaXR0ci92aWduZXR0ZXMvbWFncml0dHIuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIHVzZSB0aGUgY29tcG91bmQgYXNzaWdubWVudCBwaXBlIG9wZXJhdG9yIGAlPD4lYApbc3RyaW5ncl0oaHR0cHM6Ly9zdHJpbmdyLnRpZHl2ZXJzZS5vcmcvYXJ0aWNsZXMvc3RyaW5nci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gbWFuaXB1bGF0ZSB0aGUgY2hhcmFjdGVyIHN0cmluZ3Mgd2l0aGluIHRoZSBkYXRhICAKW3B1cnJyXShodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgfCB0byBpbXBvcnQgdGhlIGRhdGEgaW4gYWxsIHRoZSBkaWZmZXJlbnQgZXhjZWwgYW5kIGNzdiBmaWxlcyBlZmZpY2llbnRseQpbZHBseXJdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGFycmFuZ2UvZmlsdGVyL3NlbGVjdC9jb21wYXJlIHNwZWNpZmljIHN1YnNldHMgb2YgdGhlIGRhdGEgIApbcmVhZHJdKGh0dHBzOi8vcmVhZHIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGltcG9ydCB0aGUgQ1NWIGZpbGUgZGF0YQpbdGlkeXJdKGh0dHBzOi8vdGlkeXIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHJlYXJyYW5nZSBkYXRhIGluIHdpZGUgYW5kIGxvbmcgZm9ybWF0cyAKW2dncGxvdDJdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICB8IHRvIG1ha2UgdmlzdWFsaXphdGlvbnMgd2l0aCBtdWx0aXBsZSBsYXllcnMKW3NjYWxlc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3NjYWxlcy9zY2FsZXMucGRmKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gYWxsb3cgdXMgdG8gbG9vayBhdCB0aGUgY29sb3JzIHdpdGhpbiB0aGUgdmlyaWRpcyBwYWNrYWdlClt2aXJpZGlzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdmlyaWRpcy92aWduZXR0ZXMvaW50cm8tdG8tdmlyaWRpcy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gbWFrZSBwbG90cyB3aXRoIGEgY29sb3IgcGFsZXR0ZSB0aGF0IGlzIGNvbXBhdGlibGUgd2l0aCBjb2xvciBibGluZG5lc3MKW2ZvcmNhdHNdKGh0dHBzOi8vZm9yY2F0cy50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICB8IHRvIGFsbG93IGZvciByZW9yZGVyaW5nIG9mIGZhY3RvcnMgaW4gcGxvdHMKW25hbmlhcl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL25hbmlhci92aWduZXR0ZXMvZ2V0dGluZy1zdGFydGVkLXctbmFuaWFyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gIHwgdG8gbWFrZSBhIHZpc3VhbGl6YXRpb24gb2YgbWlzc2luZyBkYXRhCltzeXJ2cl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3NydnlyL3NydnlyLnBkZil7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIHVzZSBzdXJ2ZXkgd2VpZ2h0cwpbY293cGxvdF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2Nvd3Bsb3QvdmlnbmV0dGVzL2ludHJvZHVjdGlvbi5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gYWxsb3cgcGxvdHMgdG8gYmUgY29tYmluZWQgCgoKVGhlIGZpcnN0IHRpbWUgd2UgdXNlIGEgZnVuY3Rpb24sIHdlIHdpbGwgdXNlIHRoZSBgOjpgIHRvIGluZGljYXRlIHdoaWNoIHBhY2thZ2Ugd2UgYXJlIHVzaW5nLiBVbmxlc3Mgd2UgaGF2ZSBvdmVybGFwcGluZyBmdW5jdGlvbiBuYW1lcywgdGhpcyBpcyBub3QgbmVjZXNzYXJ5LCBidXQgd2Ugd2lsbCBpbmNsdWRlIGl0IGhlcmUgdG8gYmUgaW5mb3JtYXRpdmUgYWJvdXQgd2hlcmUgdGhlIGZ1bmN0aW9ucyB3ZSB3aWxsIHVzZSBjb21lIGZyb20uCgoKIyMgKipDb250ZXh0KioKKioqIAoKQWNjb3JkaW5nIHRvIHRoZSBjaXRlZCBbTW9yYmlkaXR5IGFuZCBNb3J0YWxpdHkgV2Vla2x5IFJlcG9ydF0oaHR0cHM6Ly93d3cuY2RjLmdvdi9tbXdyL3ZvbHVtZXMvNjgvd3IvbW02ODA2ZTEuaHRtP3NfY2lkPW1tNjgwNmUxX3cpIHRoaXMgd2FzIHdoYXQgd2FzIGFscmVhZHkga25vd24gYWJvdXQgdGhpcyB0b3BpYyBhbmQgdGhlIGltcGxpY2F0aW9ucyBvZiB0aGlzIHN0dWR5OgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIiwgb3V0LndpZHRoID0gIjgwMCBweCJ9Cgprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiY29udGV4dC5wbmciKSkKCmBgYAoKCkltcG9ydGFudGx5LCB0aGUgdmFwb3JzIHVzZWQgaW4gZS1jaWdhcmV0dGVzIGNvbnRhaW4gaGFybWZ1bCBjaGVtaWNhbHM6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIifQoKaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly93d3cuY2RjLmdvdi90b2JhY2NvL2Jhc2ljX2luZm9ybWF0aW9uL2UtY2lnYXJldHRlcy9pbWFnZXMvZS1jaWdhcmV0dGUtYWVyb3NvbC1jYW4tY29udGFpbi1oYXJtZnVsLWluZ3JlZGllbnRzLWRlc2t0b3AtNzAwLmpwZyIpCmBgYAoKIyMjIyBbW3NvdXJjZV0oaHR0cHM6Ly93d3cuY2RjLmdvdi90b2JhY2NvL2Jhc2ljX2luZm9ybWF0aW9uL2UtY2lnYXJldHRlcy9pbWFnZXMvZS1jaWdhcmV0dGUtYWVyb3NvbC1jYW4tY29udGFpbi1oYXJtZnVsLWluZ3JlZGllbnRzLWRlc2t0b3AtNzAwLmpwZylde3RhcmdldD0iX2JsYW5rIn0gCgpFLWNpZ2FyZXR0ZSB1c2FnZSBoYXMgYWxzbyBiZWVuIGFzc29jaWF0ZWQgd2l0aCBbbHVuZyBpbmp1cnldKChodHRwczovL3d3dy5mcm9udGllcnNpbi5vcmcvYXJ0aWNsZXMvMTAuMzM4OS9mcGhhci4yMDE5LjAxNjE5L2Z1bGwpKXt0YXJnZXQ9Il9ibGFuayJ9OgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIiwgb3V0LndpZHRoID0gIjgwMCBweCJ9Cgprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAibHVuZy5wbmciKSkKYGBgCgojIyMjIFtbc291cmNlXShodHRwczovL3d3dy5mcm9udGllcnNpbi5vcmcvYXJ0aWNsZXMvMTAuMzM4OS9mcGhhci4yMDE5LjAxNjE5L2Z1bGwpXXt0YXJnZXQ9Il9ibGFuayJ9IAoKU2VlIFtoZXJlXShodHRwczovL3d3dy5jZGMuZ292L3RvYmFjY28vYmFzaWNfaW5mb3JtYXRpb24vZS1jaWdhcmV0dGVzL1F1aWNrLUZhY3RzLW9uLXRoZS1SaXNrcy1vZi1FLWNpZ2FyZXR0ZXMtZm9yLUtpZHMtVGVlbnMtYW5kLVlvdW5nLUFkdWx0cy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIGFib3V0IHRoZSBwb3RlbnRpYWwgaGVhbHRoIGVmZmVjdHMgb2YgZS1jaWdhcmV0dGVzIGluIHRlZW5zIGFuZCB5b3VuZyBhZHVsdHMuCgojIyAqKkxpbWl0YXRpb25zKioKKioqIApUaGVyZSBhcmUgc29tZSBpbXBvcnRhbnQgY29uc2lkZXJhdGlvbnMgcmVnYXJkaW5nIHRoaXMgZGF0YSBhbmFseXNpcyB0byBrZWVwIGluIG1pbmQ6IAoKMSkgVGhlIFtOYXRpb25hbCBZb3V0aCBUb2JhY2NvIFN1cnZleSAoTllUUyldKGh0dHBzOi8vd3d3LmNkYy5nb3YvdG9iYWNjby9kYXRhX3N0YXRpc3RpY3Mvc3VydmV5cy9ueXRzL2luZGV4Lmh0bSl7dGFyZ2V0PSJfYmxhbmsifSBkb2VzIG5vdCBmb2xsb3cgdGhlIHNhbWUgaW5kaXZpZHVhbCBzdHVkZW50cyBvdmVyIHRpbWUuICBBIFtsb25naXR1ZGluYWwgc3R1ZHldKGh0dHBzOi8vd3d3LmJtai5jb20vYWJvdXQtYm1qL3Jlc291cmNlcy1yZWFkZXJzL3B1YmxpY2F0aW9ucy9lcGlkZW1pb2xvZ3ktdW5pbml0aWF0ZWQvNy1sb25naXR1ZGluYWwtc3R1ZGllcyl7dGFyZ2V0PSJfYmxhbmsifSB0aGF0IGRvZXMgZm9sbG93IHRoZSBzYW1lIGluZGl2aWR1YWxzIG92ZXIgdGltZSBjb2xsZWN0cyBkYXRhIGNhbGxlZCBbcGFuZWwgZGF0YV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUGFuZWxfZGF0YSkuIFRoZSBkYXRhIGluIHRoaXMgc3R1ZHkgaXMgY2FsbGVkIHBvb2xlZCBbY3Jvc3Mtc2VjdGlvbmFsIGRhdGFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Nyb3NzLXNlY3Rpb25hbF9kYXRhKSwgYW5kIGlzIG9idGFpbmVkIGZyb20gcmFuZG9tIGNvbGxlY3Rpb24gb2Ygb2JzZXJ2YXRpb25zIGFjcm9zcyB0aW1lLgoKQWNjb3JkaW5nIHRvIFdpa2lwZWRpYToKCj4gUGFuZWwgZGF0YSBkaWZmZXJzIGZyb20gcG9vbGVkIGNyb3NzLXNlY3Rpb25hbCBkYXRhIGFjcm9zcyB0aW1lLCBiZWNhdXNlIGl0IGRlYWxzIHdpdGggdGhlIG9ic2VydmF0aW9ucyBvbiB0aGUgc2FtZSBzdWJqZWN0cyBpbiBkaWZmZXJlbnQgdGltZXMgd2hlcmVhcyB0aGUgbGF0dGVyIG9ic2VydmVzIGRpZmZlcmVudCBzdWJqZWN0cyBpbiBkaWZmZXJlbnQgdGltZSBwZXJpb2RzCgoyKSBUaGUgZGF0YSBpbmNsdWRlIHBlcmNlbnRhZ2VzIG9mIHN0dWRlbnRzIHJlcG9ydGluZyB1c2Ugb2YgZWFjaCBwYXJ0aWN1bGFyIHRvYmFjY28gcHJvZHVjdCwgYnV0IHRoZSBzdXJ2ZXkgcXVlc3Rpb25zIGRpZCBub3QgYXNrIHRoZSByZWxhdGl2ZSBhbW91bnQgb2YgdXNlIG9mIG9uZSBwcm9kdWN0IGNvbXBhcmVkIHRvIGFub3RoZXIuIEZvciBleGFtcGxlIHRoZSBzdXJ2ZXkgaW5jbHVkZWQgcXVlc3Rpb25zIGxpa2U6IldoYXQgZmxhdm9ycyBvZiB0b2JhY2NvIHByb2R1Y3RzIGhhdmUgeW91IHVzZWQgaW4gdGhlIHBhc3QgMzAgZGF5cz8iIGJ1dCBkaWQgbm90IGFzayBob3cgb2Z0ZW4gb25lIGZsYXZvciB3YXMgdXNlZCBieSB0aGUgc2FtZSBpbmRpdmlkdWFsIG92ZXIgYW5vdGhlci4KCldoaWxlIFtnZW5kZXJdKGh0dHBzOi8vd3d3LmdlbmRlcnNwZWN0cnVtLm9yZy9xdWljay1saW5rcy91bmRlcnN0YW5kaW5nLWdlbmRlci8pe3RhcmdldD0iX2JsYW5rIn0gYW5kIFtzZXhdKGh0dHBzOi8vd3d3Lndoby5pbnQvZ2Vub21pY3MvZ2VuZGVyL2VuL2luZGV4MS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IGFyZSBub3QgYWN0dWFsbHkgYmluYXJ5LCB0aGUgZGF0YSB1c2VkIGluIHRoaXMgYW5hbHlzaXMgb25seSBjb250YWluIGluZm9ybWF0aW9uIGZvciBncm91cHMgb2YgaW5kaXZpZHVhbHMgd2hvIGFuc3dlcmVkIHRoZSBzdXJ2ZXkgcXVlc3Rpb25zIGFzIG1hbGUgb3IgZmVtYWxlLiAKCiMjICoqV2hhdCBhcmUgdGhlIGRhdGE/KioKKioqIAogClRoZSBkYXRhIGluIHRoaXMgY2FzZSBzdHVkeSBjb21lcyBmcm9tIHRoZSBbTmF0aW9uYWwgWW91dGggVG9iYWNjbyBTdXJ2ZXkgKE5ZVFMpXShodHRwczovL3d3dy5jZGMuZ292L3RvYmFjY28vZGF0YV9zdGF0aXN0aWNzL3N1cnZleXMvbnl0cy9pbmRleC5odG0pe3RhcmdldD0iX2JsYW5rIn0gd2hpY2ggaXMgYW4gYW5udWFsIHN1cnZleSB0aGF0IGFza3Mgc3R1ZGVudHMgIGluIGhpZ2ggc2Nob29sIGFuZCBtaWRkbGUgc2Nob29sIChncmFkZXMgNi0xMikgYWJvdXQgdG9iYWNjbyB1c2FnZSBpbiB0aGUgVW5pdGVkIFN0YXRlcyBvZiBBbWVyaWNhLgoKVGhlIGRhdGEgZm9yIHRoaXMgc3VydmV5IGlzIGZyZWVseSBhdmFpbGFibGUgb25saW5lIGF0IHRoaXMgW3dlYnNpdGVdKGh0dHBzOi8vd3d3LmNkYy5nb3YvdG9iYWNjby9kYXRhX3N0YXRpc3RpY3Mvc3VydmV5cy9ueXRzL2RhdGEvaW5kZXguaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSB3aXRoIGRhdGEgZnJvbSAxOTk5LCAyMDAwLCAyMDAyLCAyMDA0LCAyMDA2LCAyMDA5LCAgYW5kIDIwMTEtMjAxOS4gV2Ugd2lsbCBiZSB1c2luZyBkYXRhIGZyb20gKioyMDE1LTIwMTkqKiBkdWUgdG8gdGhlIGZhY3QgdGhhdCB0aGVzZSB5ZWFycyBhcmUgdGhlIG1vc3QgcmVjZW50IHRoYXQgYXNrZWQgcXVlc3Rpb25zIHJlZ2FyZGluZyBlLWNpZ2FyZXR0ZSB1c2FnZS4KCkVhY2ggeWVhciBpbmNsdWRlcyBkb2N1bWVudGF0aW9uLCBzdWNoIGFzIGEgW2NvZGVib29rXShodHRwczovL3d3dy5saWIubmNzdS5lZHUvZGF0YS9pY3BzcmZhcSN3aGF0YXJlKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCBhbiBleGNlbCBmaWxlIGNvbnRhaW5pbmcgdGhlIGRhdGE6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIiLCBvdXQud2lkdGggPSAiNjAwIHB4In0KCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJkYXRhLnBuZyIpKQpgYGAKVGhlcmVmb3JlLCBzaW5jZSB3ZSBhcmUgdXNpbmcgZGF0YSBmcm9tICoqMjAxNS0yMDE5KiosIHRoZSBkYXRhIHdlIGFyZSBpbnRlcmVzdGVkIGluIGFyZSBsb2NhdGVkIGluIDUgZGlmZmVyZW50IGV4Y2VsIGZpbGVzLCBvbmUgZm9yIGVhY2ggeWVhciwgZWFjaCB3aXRoIGl0cyBvd24gW2NvZGVib29rXSguL2RvY3MvMjAxOS1ueXRzLWRhdGFzZXQtYW5kLWNvZGVib29rLW1pY3Jvc29mdC1leGNlbC8yMDE5LW55dHMtY29kZWJvb2stcC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gKHRoaXMgaXMgdGhlIG9uZSBmb3IgMjAxOSkuCgpUaGUgY29kZWJvb2sgY29udGFpbnMgaW5mb3JtYXRpb24gZGVzY3JpYmluZyB0aGUgZGF0YSB3aXRoaW4gdGhlIGV4Y2VsIGZpbGUuIAoKQXMgeW91IGNhbiBzZWUgdGhlIGV4Y2VsIGZpbGUgY29udGFpbnMgdmVyeSBzaG9ydCB2YXJpYWJsZSBuYW1lcyBhbmQgbnVtZXJpYyB2YWx1ZXMsIGFuZCBpdCBpcyBub3QgY2xlYXIgd2hhdCB0aGV5IG1lYW4gd2l0aG91dCB0aGUgY29kZWJvb2s6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIiLCBvdXQud2lkdGggPSAiNjAwIHB4In0KCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJleGNlbC5wbmciKSkKYGBgCgpUaGUgY29kZWJvb2sgZXhwbGFpbnMgd2hhdCB0aGUgdmFyaWFibGVzICh0aGUgY29sdW1ucykgYXJlOgpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIiLCBvdXQud2lkdGggPSAiNjAwIHB4In0KCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJ2YXJpYWJsZXMucG5nIikpCmBgYAoKQW5kIHRoZSBjb2RlYm9vayBleHBsYWlucyB3aGF0IHRoZSB2YWx1ZXMgZm9yIGVhY2ggdmFyaWFibGUgYXJlOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIiwgb3V0LndpZHRoID0gIjYwMCBweCJ9Cgprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAicW4xLnBuZyIpKQpgYGAKCldlIHdpbGwgZXhwbGFpbiBtb3JlIGxhdGVyIGFib3V0IHdoYXQgdGhlIHZhbHVlcyBvbiB0aGUgcmlnaHQgaW5kaWNhdGUuCgpUaGUgcmVhc29uIHRoYXQgdGhlcmUgYXJlIGNvZGVib29rcyBmb3IgZWFjaCB5ZWFyIGlzIGJlY2F1c2UgdGhlIHF1ZXN0aW9ucyBhc2tlZCBlYWNoIHllYXIgdmFyaWVkIHNsaWdodGx5LgoKClRoZSBkYXRhIGluIHRoaXMgc3VydmV5IGFyZSBwb29sZWQgY3Jvc3Mtc2VjdGlvbmFsIGRhdGEuIEluIHRoaXMgc3R1ZHkgZGVzaWduLCBkaWZmZXJlbnQgc3Vic2V0cyBvZiBzdHVkZW50cyBhcmUgc3VydmV5ZWQgZWFjaCB5ZWFyIGFuZCBpdCBpcyBub3QgY2xlYXIgd2hpY2gsIGlmIGFueSwgaW5kaXZpZHVhbHMgcGFydGljaXBhdGUgbW9yZSB0aGFuIG9uY2UgZnJvbSBvbmUgeWVhciB0byB0aGUgbmV4dC4KCiMjICoqRGF0YSBJbXBvcnQqKgoqKiogCgojIyMgUmVhZGluZyBpbiB0aGUgZXhjZWwgZmlsZXMKKioqClNpbmNlIHRoZXNlIGV4Y2VsIGZpbGVzIGFyZSBzbyBsYXJnZSAoZWFjaCBoYXMgcm91Z2hseSAyMCwwMDAgcm93cyksIGl0IHRha2VzIGEgYml0IG9mIHRpbWUgZm9yIHRoZSBkYXRhIHRvIGxvYWQuIFRvIG1ha2UgdGhlIHByb2Nlc3MgZmFzdGVyLCB3ZSBwcmV2aW91c2x5IGltcG9ydGVkIHRoZXNlIGZpbGVzLCBzZWxlY3RlZCBvbmx5IHRoZSBjb2x1bW5zIHJlbGV2YW50IHRvIG91ciBxdWVzdGlvbnMgb2YgaW50ZXJlc3QsIGFuZCBzYXZlZCB0aGVzZSBkYXRhIHN1YnNldHMgYXMgY29tbWEtc2VwYXJhdGVkICguY3N2KSBmaWxlcy4gCgo8ZGV0YWlscz48c3VtbWFyeT4gQ2xpY2sgaGVyZSBmb3IgZGV0YWlscyBvbiBob3cgdGhlIGRhdGEgd2VyZSBvcmlnaW5hbGx5IGltcG9ydGVkIDwvc3VtbWFyeT4KCkZpcnN0IHdlIGNyZWF0ZWQgYSB2ZWN0b3Igb2YgZmlsZSBuYW1lcyBvZiBhbGwgdGhlIGRpZmZlcmVudCBleGNlbCBmaWxlcy4gVXNpbmcgdGhlIGBoZXJlKClgIGZ1bmN0aW9uIG9mIHRoZSBgaGVyZWAgcGFja2FnZSwgd2UgbG9va2VkIGluIGFsbCB0aGUgZGlyZWN0b3JpZXMgb2YgdGhlIHByb2plY3QuClRoZSBgbGlzdC5maWxlcygpYCBmdW5jdGlvbiBsb29rZWQgZm9yIGFsbCBmaWxlcyB3aXRoIC54bHN4IHdpdGhpbiB0aGVzZSBzdWItZGlyZWN0b3JpZXMuCmBgYHtyfQpleGNlbF9maWxlczwtbGlzdC5maWxlcyhoZXJlOjpoZXJlKCksIHJlY3Vyc2l2ZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiKi54bHN4IikKZXhjZWxfZmlsZXMKYGBgCgpBbGwgdGhlIGZpbGVzIHdlcmUgcmVhZCB1c2luZyBgcmVhZF9leGNlbCgpYCBvZiB0aGUgYHJlYWR4bGAgcGFja2FnZS4gVXNpbmcgdGhlIGBtYXAoKWAgZnVuY3Rpb24gb2YgdGhlIGBwdXJycmAgcGFja2FnZSB0aGlzIHdhcyBkb25lIGVmZmljaWVudGx5IGZvciBhbGwgb2YgdGhlIGV4Y2VsIGZpbGVzIGluIHRoZSB2ZWN0b3IgdXNpbmcgb25lIGNvbW1hbmQuIFRoZSBgLmAgaXMgdXNlZCB0byBpbmRpY2F0ZSB0aGF0IHdlIHdhbnQgdG8gYXBwbHkgdGhlIGByZWFkX2V4Y2VsKClgIGZ1bmN0aW9uIHRvIGVhY2ggZWxlbWVudCBvZiB0aGUgZGF0YSB0aGF0IHdlIGp1c3QgcGlwZWQgaW50byB0aGUgYG1hcCgpYCBmdW5jdGlvbi4KCkhlcmUgd2UgYWxzbyB1c2VkIHRoZSBgJT4lYCBwaXBlIHdoaWNoIGNhbiBiZSB1c2VkIHRvIHBhc3MgdGhlIGlucHV0IGZyb20gb25lIGZ1bmN0aW9uIHRvIGFub3RoZXIgZm9yIGxhdGVyIHNlcXVlbnRpYWwgc3RlcHMuIAoKVGhpcyBjcmVhdGVkIGEgc2luZ2xlIGxpc3Qgb2YgdGliYmxlcyAob25lIGZvciBlYWNoIGZpbGUpLiAKYGBge3IsIGV2YWwgPSBGQUxTRX0KdGJsX2ZpbGVzIDwtIGV4Y2VsX2ZpbGVzICU+JSAKICAgICAgIG1hcCh+cmVhZHhsOjpyZWFkX2V4Y2VsKC4pKQpgYGAKClRoZSBlbGVtZW50cyBvZiB0aGlzIGxpc3QgYXJlIGluIHRoZSBzYW1lIG9yZGVyIGFzIHRoZSBlbGVtZW50cyBvZiB0aGUgYGV4Y2VsX2ZpbGVzYCB2ZWN0b3IsIHNvIHdlIGNhbiBleHRyYWN0IHRoZSBkYXRhIGZvciBhIHBhcnRpY3VsYXIgZmlsZSAoeWVhcikgYnkgc2VsZWN0aW5nIGEgY2VydGFpbiBlbGVtZW50IG9mIHRoZSBsaXN0LiBIb3dldmVyLCBpdCBpcyBzYWZlciB0byBiZSBhYmxlIHRvIHNlbGVjdCB0aGUgZGF0YSBmcm9tIHRoaXMgbGlzdCBmb3IgYSBzcGVjaWZpYyB5ZWFyIHVzaW5nIGEgbmFtZSBiYXNlZCBvbiB0aGUgb3JpZ2luYWwgdmVjdG9yIG9mIGZpbGUgbmFtZXMuIFdlIGV4dHJhY3RlZCBhIG5hbWUgZnJvbSBlYWNoIEV4Y2VsIGZpbGUgbmFtZSB1c2luZyB0aGUgYHN0cl9leHRyYWN0KClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RyaW5ncmAgcGFja2FnZS4gSGVyZSB3ZSBhcmUga2VlcGluZyBvY2N1cnJlbmNlcyBvZiB0aGUgY2hhcmFjdGVyIHN0cmluZyAibnl0czIwMSIgZm9sbG93ZWQgYnkgYSAiNSIsIjYiLCI3IiwiOCIsIG9yICI5Ii4KCmBgYHtyfQp0YmxfbmFtZXMgPC0gZXhjZWxfZmlsZXMgJT4lCiAgc3RyX2V4dHJhY3QoIm55dHMyMDFbNS05XSIpCgp0YmxfbmFtZXMKYGBgCgpUaGVzZSBuYW1lcyBiZWNhbWUgdGhlIG5hbWVzIG9mIHRoZSB0aWJibGVzIGluIHRoZSBsaXN0IG9mIHRpYmJsZXMuCmBgYHtyLCBldmFsID0gRkFMU0V9Cm5hbWVzKHRibF9maWxlcykgPC0gdGJsX25hbWVzCmBgYAoKClNwZWNpZmljIGNvbHVtbnMgd2VyZSBzZWxlY3RlZCB1c2luZyB0aGUgYHNlbGVjdCgpYCBmdW5jdGlvbiBvZiBgZHBseXJgIGZyb20gZWFjaCBvZiB0aGUgdGliYmxlcyB1c2luZyB0aGUgdmFyaWFibGUgbmFtZSwgYXMgaWRlbnRpZmllZCBpbiB0aGUgY29kZWJvb2sgYXMgYmVpbmcgb2YgaW50ZXJlc3QgZm9yIG91ciBhbmFseXNpcy4KSW4gc29tZSBjYXNlcyBmdW5jdGlvbnMgbGlrZSBgc3RhcnRzX3dpdGgoKWAgb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB3ZXJlIHVzZWQgdG8gc2VsZWN0IHNldmVyYWwgdmFyaWFibGVzIGF0IG9uY2UuIE1vc3Qgb2YgdGhlIHN1cnZleSBxdWVzdGlvbnMgYWJvdXQgdG9iYWNjbyB1c2Ugc3RhcnQgd2l0aCBhbiBgIkUiYCBvciBhIGAiQyJgIGFjY29yZGluZyB0byB0aGUgY29kZWJvb2tzLiAKCmBgYHtyLCBldmFsID0gRkFMU0V9Cgp0YmxfZmlsZXNbWyJueXRzMjAxNSJdXSA8LSB0YmxfZmlsZXNbWyJueXRzMjAxNSJdXSAlPiUKICAgIGRwbHlyOjpzZWxlY3QocHN1LCAjUHJpbWFyeSBTYW1wbGluZyBVbml0CiAgICAgICAgICAgICAgICAgIGZpbndndCwjQW5hbHlzaXMgV2VpZ2h0CiAgICAgICAgICAgICAgICAgIHN0cmF0dW0sI1NhbXBsaW5nIHN0cmF0dW0KICAgICAgICAgICAgICAgICAgUW4xLCAjQWdlCiAgICAgICAgICAgICAgICAgIFFuMiwgI1NleAogICAgICAgICAgICAgICAgICBRbjMsICNHcmFkZQogICAgICAgICAgICAgICAgICBzdGFydHNfd2l0aCgiRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICBzdGFydHNfd2l0aCgiQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICApCgoKdGJsX2ZpbGVzW1sibnl0czIwMTYiXV0gPC0gdGJsX2ZpbGVzW1sibnl0czIwMTYiXV0gJT4lCiAgICBkcGx5cjo6c2VsZWN0KHBzdSwKICAgICAgICAgICAgICAgICAgZmlud2d0LAogICAgICAgICAgICAgICAgICBzdHJhdHVtLAogICAgICAgICAgICAgICAgICBRMSwgI0FnZQogICAgICAgICAgICAgICAgICBRMiwgI1NleAogICAgICAgICAgICAgICAgICBRMywgI0dyYWRlCiAgICAgICAgICAgICAgICAgIHN0YXJ0c193aXRoKCJFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlLmNhc2UgPSBGQUxTRSksCiAgICAgICAgICAgICAgICAgIHN0YXJ0c193aXRoKCJDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlLmNhc2UgPSBGQUxTRSksCiAgICAgICAgICAgICAgICAgIFE1MEEsICNNZW50aG9sICMgV2hhdCBmbGF2b3JzIG9mIHRvYmFjY28gcHJvZHVjdHMgaGF2ZSB5b3UgdXNlZCBpbiB0aGUgcGFzdCAzMCBkYXlzPyAoU2VsZWN0IG9uZSBvciBtb3JlKQogICAgICAgICAgICAgICAgICBRNTBCLCAjQ2xvdmUgb3Igc3BpY2UKICAgICAgICAgICAgICAgICAgUTUwQywgI0ZydWl0CiAgICAgICAgICAgICAgICAgIFE1MEQsICNDaG9jb2xhdGUKICAgICAgICAgICAgICAgICAgUTUwRSwgI0FsY29ob2xpYyBEcmluawogICAgICAgICAgICAgICAgICBRNTBGLCAjQ2FuZHkvRGVzc2VydHMvT3RoZXIgU3dlZXRzCiAgICAgICAgICAgICAgICAgIFE1MEcsICNTb21lIE90aGVyIEZsYXZvciBOb3QgTGlzdGVkIEhlcmUKICAgICAgICAgICAgICAgICAgUTUwSCAjSSBEaWQgTm90IFVzZSBGbGF2b3JlZCBUb2JhY2NvIFByb2R1Y3RzIEluIHRoZSBQYXN0CiAgICAgICAgICAgICAgICAgICkgCgp0YmxfZmlsZXNbWyJueXRzMjAxNyJdXSA8LSB0YmxfZmlsZXNbWyJueXRzMjAxNyJdXSAlPiUKICAgIGRwbHlyOjpzZWxlY3QocHN1LAogICAgICAgICAgICAgICAgICBmaW53Z3QsCiAgICAgICAgICAgICAgICAgIHN0cmF0dW0sCiAgICAgICAgICAgICAgICAgIFExLCAjQWdlCiAgICAgICAgICAgICAgICAgIFEyLCAjU2V4CiAgICAgICAgICAgICAgICAgIFEzLCAjR3JhZGUKICAgICAgICAgICAgICAgICAgc3RhcnRzX3dpdGgoIkUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZ25vcmUuY2FzZSA9IEZBTFNFKSwKICAgICAgICAgICAgICAgICAgc3RhcnRzX3dpdGgoIkMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZ25vcmUuY2FzZSA9IEZBTFNFKSwKICAgICAgICAgICAgICAgICAgUTUwQSwgI01lbnRob2wgIyBXaGF0IGZsYXZvcnMgb2YgdG9iYWNjbyBwcm9kdWN0cyBoYXZlIHlvdSB1c2VkIGluIHRoZSBwYXN0IDMwIGRheXM/IChTZWxlY3Qgb25lIG9yIG1vcmUpCiAgICAgICAgICAgICAgICAgIFE1MEIsICNDbG92ZSBvciBzcGljZQogICAgICAgICAgICAgICAgICBRNTBDLCAjRnJ1aXQKICAgICAgICAgICAgICAgICAgUTUwRCwgI0Nob2NvbGF0ZQogICAgICAgICAgICAgICAgICBRNTBFLCAjQWxjb2hvbGljIERyaW5rCiAgICAgICAgICAgICAgICAgIFE1MEYsICNDYW5keS9EZXNzZXJ0cy9PdGhlciBTd2VldHMKICAgICAgICAgICAgICAgICAgUTUwRywgI1NvbWUgT3RoZXIgRmxhdm9yIE5vdCBMaXN0ZWQgSGVyZQogICAgICAgICAgICAgICAgICBRNTBIICNJIERpZCBOb3QgVXNlIEZsYXZvcmVkIFRvYmFjY28gUHJvZHVjdHMgSW4gdGhlIFBhc3QKICAgICAgICAgICAgICAgICAgKQoKdGJsX2ZpbGVzW1sibnl0czIwMTgiXV0gPC0gdGJsX2ZpbGVzW1sibnl0czIwMTgiXV0gJT4lCiAgICBkcGx5cjo6c2VsZWN0KHBzdSwKICAgICAgICAgICAgICAgICAgZmlud2d0LAogICAgICAgICAgICAgICAgICBzdHJhdHVtLAogICAgICAgICAgICAgICAgICBRMSwgI0FnZQogICAgICAgICAgICAgICAgICBRMiwgI1NleAogICAgICAgICAgICAgICAgICBRMywgI0dyYWRlCiAgICAgICAgICAgICAgICAgIHN0YXJ0c193aXRoKCJFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlLmNhc2UgPSBGQUxTRSksCiAgICAgICAgICAgICAgICAgIHN0YXJ0c193aXRoKCJDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlLmNhc2UgPSBGQUxTRSksCiAgICAgICAgICAgICAgICAgIFE1MEEsICNNZW50aG9sICMgV2hhdCBmbGF2b3JzIG9mIHRvYmFjY28gcHJvZHVjdHMgaGF2ZSB5b3UgdXNlZCBpbiB0aGUgcGFzdCAzMCBkYXlzPyAoU2VsZWN0IG9uZSBvciBtb3JlKQogICAgICAgICAgICAgICAgICBRNTBCLCAjQ2xvdmUgb3Igc3BpY2UKICAgICAgICAgICAgICAgICAgUTUwQywgI0ZydWl0CiAgICAgICAgICAgICAgICAgIFE1MEQsICNDaG9jb2xhdGUKICAgICAgICAgICAgICAgICAgUTUwRSwgI0FsY29ob2xpYyBEcmluawogICAgICAgICAgICAgICAgICBRNTBGLCAjQ2FuZHkvRGVzc2VydHMvT3RoZXIgU3dlZXRzCiAgICAgICAgICAgICAgICAgIFE1MEcsICNTb21lIE90aGVyIEZsYXZvciBOb3QgTGlzdGVkIEhlcmUKICAgICAgICAgICAgICAgICAgUTUwSCAjSSBEaWQgTm90IFVzZSBGbGF2b3JlZCBUb2JhY2NvIFByb2R1Y3RzIEluIHRoZSBQYXN0CiAgICAgICAgICAgICAgICAgICkKCnRibF9maWxlc1tbIm55dHMyMDE5Il1dIDwtIHRibF9maWxlc1tbIm55dHMyMDE5Il1dICU+JQogICAgZHBseXI6OnNlbGVjdChwc3UsCiAgICAgICAgICAgICAgICAgIGZpbndndCwKICAgICAgICAgICAgICAgICAgc3RyYXR1bSwKICAgICAgICAgICAgICAgICAgUTEsICNBZ2UKICAgICAgICAgICAgICAgICAgUTIsICNTZXgKICAgICAgICAgICAgICAgICAgUTMsICNHcmFkZQogICAgICAgICAgICAgICAgICBzdGFydHNfd2l0aCgiRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICBzdGFydHNfd2l0aCgiQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICBRNDAsICNCcmFuZCwgZS1jaWdhcmV0dGVzCiAgICAgICAgICAgICAgICAgIFE2MkEsICNNZW50aG9sICMgV2hhdCBmbGF2b3JzIG9mIHRvYmFjY28gcHJvZHVjdHMgaGF2ZSB5b3UgdXNlZCBpbiB0aGUgcGFzdCAzMCBkYXlzPyAoU2VsZWN0IG9uZSBvciBtb3JlKQogICAgICAgICAgICAgICAgICBRNjJCLCAjQ2xvdmUgb3Igc3BpY2UKICAgICAgICAgICAgICAgICAgUTYyQywgI0ZydWl0IAogICAgICAgICAgICAgICAgICBRNjJELCAjQ2hvY29sYXRlCiAgICAgICAgICAgICAgICAgIFE2MkUsICNBbGNvaG9saWMgRHJpbmsKICAgICAgICAgICAgICAgICAgUTYyRiwgI0NhbmR5L0Rlc3NlcnRzL090aGVyIFN3ZWV0cwogICAgICAgICAgICAgICAgICBRNjJHLCAjU29tZSBPdGhlciBGbGF2b3IgTm90IExpc3RlZCBIZXJlIAogICAgICAgICAgICAgICAgICApCgpgYGAKCkEgZGlyZWN0b3J5IGNhbGxlZCBgZGF0YV9yZWR1Y2VkYCB3YXMgY3JlYXRlZCBmb3IgdGhlIG5ldyAuY3N2IGZpbGVzIHVzaW5nIHRoZSBiYXNlIGBkaXIuY3JlYXRlKClgIGZ1bmN0aW9uLiAKQSBjc3YgZmlsZSB3YXMgY3JlYXRlZCBmb3IgZWFjaCBvZiB0aGUgdGliYmxlcyBpbiB0aGUgbGlzdCB1c2luZyB0aGUgYHdyaXRlX2NzdigpYCBmdW5jdGlvbiBvZiB0aGUgYHJlYWRyYCBwYWNrYWdlLgpUaGlzIHdhcyBkb25lIGFsbCBhdCBvbmNlIHVzaW5nIHRoZSBgbWFwKClgIGZ1bmN0aW9uLgoKQVZPQ0FETzogSSBnb3QgaXQgdG8gd29yayB1c2luZyBtYXA7IGhvcGVmdWxseSB0aGlzIGlzIE9LPwoKYGBge3IsIGV2YWwgPSBGQUxTRX0KIyAKZGlyLmNyZWF0ZSgiZG9jcy9kYXRhX3JlZHVjZWQiKQoKbmFtZXModGJsX2ZpbGVzKSAlPiUgbWFwKH53cml0ZV9jc3YodGJsX2ZpbGVzW1suXV0sIHBhdGg9cGFzdGUwKCJkb2NzL2RhdGFfcmVkdWNlZC8iLCAuLCAiLmNzdiIpKSkgICAKCmBgYAoKPC9kZXRhaWxzPgoKCgpOb3cgd2Ugd2lsbCBzaG93IGhvdyB0byByZWFkIGluIHRoZSBkYXRhIGZyb20gdGhlIGZpdmUgY3N2IGZpbGVzIHRoYXQgd2VyZSBjcmVhdGVkIGZyb20gdGhlIGZpdmUgZGlmZmVyZW50IEV4Y2VsIGZpbGVzLgoKIyMjIFJlYWRpbmcgaW4gdGhlIENTViBmaWxlcwoqKioKCgpgYGB7cn0Kbnl0c19kYXRhIDwtIGxpc3QuZmlsZXMoaGVyZTo6aGVyZSgpLHJlY3Vyc2l2ZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIiouY3N2IiklPiUKICBtYXAofnJlYWRfY3N2KC4pKQoKCm55dHNfZGF0YV9uYW1lcyA8LSBsaXN0LmZpbGVzKHJlY3Vyc2l2ZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIiouY3N2IiklPiUKICBzdHJfZXh0cmFjdCgibnl0czIwMVs1LTldIikKCm5hbWVzKG55dHNfZGF0YSkgPC0gbnl0c19kYXRhX25hbWVzCmBgYAoKCiMjICoqRGF0YSBFeHBsb3JhdGlvbiBhbmQgV3JhbmdsaW5nKioKKioqIAoKT3VyIGdvYWwgaW4gdGhpcyBzZWN0aW9uIGlzIHRvIGFkanVzdCBvciAid3JhbmdsZSIgdGhlIGRhdGEgZnJvbSBlYWNoIHllYXIgaW50byBhIGNvbW1vbiBmb3JtYXQgc28gdGhhdCB3ZSBjYW4gY29tYmluZSB0aGUgZGF0YSBzZXRzIGFjcm9zcyB5ZWFycyBmb3Igb3VyIGFuYWx5c2lzLCBhbmQgc28gdGhhdCB3ZSBoYXZlIHZhbHVlcyBpbiBvdXIgdmFyaWFibGVzIHRoYXQgYXJlIGNvcnJlY3QgYW5kIGVhc3kgdG8gaW50ZXJwcmV0LiBXZSB3aWxsIG5lZWQgdG8gdW5kZXJzdGFuZCB3aGF0IGlzIHRoZSBzYW1lIGFuZCB3aGF0IGlzIGRpZmZlcmVudCBhY3Jvc3MgdGhlIGRhdGEgZnJvbSBkaWZmZXJlbnQgeWVhcnMsIHJlbmFtZSBhbmQgcmVjb2RlIHRoZSB2YXJpYWJsZXMgKGUuZy4sIGJ5IHJlcGxhY2luZyB0aGUgbnVtYmVycyAxIGFuZCAyIHdpdGggdGhlIHZhbHVlcyAiTWFsZSIgYW5kICJGZW1hbGUiIGZvciB0aGUgYFNleGAgdmFyaWFibGUpLCBhbmQgY29tYmluZSB0aGUgZGF0YS4gV2Ugd2lsbCB3YWxrIHRocm91Z2ggdGhlc2Ugc3RlcHMgYmVsb3cuIAoKRmlyc3QsIGxldCdzIHRha2UgYSBsb29rIGF0IG91ciBkYXRhLiBXZSBjYW4gZ2V0IGEgZ29vZCBzZW5zZSBvZiBpdCB1c2luZyB0aGUgYGdsaW1wc2UoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4KCiMjIyMgey5zY3JvbGxhYmxlIH0KCmBgYHtyfQpkcGx5cjo6Z2xpbXBzZShueXRzX2RhdGFbWyJueXRzMjAxNSJdXSkKYGBgCiMjIyMKCiMjIyBVcGRhdGluZyB0aGUgc2V0IG9mIHZhcmlhYmxlcyBhbmQgdGhlaXIgbmFtZXMKKioqIAoKVGhlIGVhc2llc3Qgd2F5IG9mIG1ha2luZyBpdCBzbyB0aGF0IHRoZSBkYXRhIGZyb20gdGhlIGRpZmZlcmVudCB5ZWFycyBjYW4gYmUgY29tYmluZWQgaXMgYnkgbWFraW5nIHN1cmUgdGhlIGRpZmZlcmVudCBkYXRhIHNldHMgYWxsIGNvbnRhaW4gdGhlIHNhbWUgdmFyaWFibGVzIHRoYXQgc2hhcmUgdGhlIHNhbWUgbmFtZXMuIEluIGFkZGl0aW9uLCBnaXZpbmcgdGhlIGNvbHVtbnMgaW5mb3JtYXRpdmUgbmFtZXMgd2lsbCBoZWxwIG1ha2Ugb3VyIGNvZGUgbW9yZSByZWFkYWJsZS4gQ3VycmVudGx5LCBpdCBpc24ndCB2ZXJ5IGNsZWFyIHdoYXQgbW9zdCBvZiB0aGUgdmFyaWFibGVzIGluZGljYXRlIHNpbmNlIHRoZSB2YXJpYWJsZSBuYW1lcyBhcmUgdW5pbmZvcm1hdGl2ZSBvbiB0aGVpciBvd24sIHdpdGhvdXQgdGhlIFtjb2RlYm9va10oLi9kb2NzLzIwMTktbnl0cy1kYXRhc2V0LWFuZC1jb2RlYm9vay1taWNyb3NvZnQtZXhjZWwvMjAxOS1ueXRzLWNvZGVib29rLXAucGRmKXt0YXJnZXQ9Il9ibGFuayJ9LgoKV2Ugd2FudCB0byByZW5hbWUgdmFyaWFibGVzIGxpa2UgYFFuMWAgdG8gc29tZXRoaW5nIG1vcmUgbWVhbmluZ2Z1bCBsaWtlIGBBZ2VgLgoKVG8gZG8gdGhpcyB3ZSB3aWxsIHVzZSB0aGUgYHJlbmFtZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBUaGUgbmV3IG5hbWUgaXMgYWx3YXlzIGxpc3RlZCBmaXJzdCBiZWZvcmUgdGhlIGA9YC4gVGhpcyBmdW5jdGlvbiB3aWxsIHJlcGxhY2UgdGhlIG9sZCB2YXJpYWJsZSBuYW1lcyB3aXRoIHRoZSBuZXcgb25lcywgaS5lLiwgYWZ0ZXIgcnVubmluZyB0aGUgY29kZSBiZWxvdywgdGhlcmUgd2lsbCBubyBsb25nZXIgYmUgYSBgUW4xYCB2YXJpYWJsZSBpbiB0aGUgZGF0YSBzZXQsIGJ1dCB0aGVyZSB3aWxsIGJlIGFuIGBBZ2VgIHZhcmlhYmxlIGluc3RlYWQuIFdlIHdpbGwgc3RhcnQgd29ya2luZyB3aXRoIHRoZSAyMDE1IGRhdGEsIGFuZCB0aGVuIG1vdmUgb24gdG8gdGhlIG90aGVyIHllYXJzIGRvd24gYmVsb3cuCgpgYGB7cn0KCm55dHNfZGF0YVtbIm55dHMyMDE1Il1dIDwtIG55dHNfZGF0YVtbIm55dHMyMDE1Il1dICU+JQogICAgZHBseXI6OnJlbmFtZShBZ2U9UW4xLAogICAgICAgICAgIFNleD1RbjIsCiAgICAgICAgICAgR3JhZGU9UW4zKQpgYGAKCgpBVk9DQURPOiBJIGxhdGVyIGxlYXJuZWQgdGhhdCBpdCBpcyBub3QgY29ycmVjdCB0aGF0IHdlIG5lZWQgdGhlIHNhbWUgdmFyaWFibGVzIGluIHRoZSBkYXRhIHNldCB3aGVuIHVzaW5nIGJpbmRfcm93cywgc28gd2h5IGFyZSB3ZSBjcmVhdGluZyB0aGVzZSBkdW1teSB2YXJpYWJsZXMgd2l0aCBOQXMgaGVyZT8gV29uJ3QgdGhleSBiZSBhdXRvbWF0aWNhbGx5IGNyZWF0ZWQgbGF0ZXIgaW4gYW55IGNhc2U/CgpXZSBhbHNvIG5lZWQgdG8gYWRkIG5ldyB2YXJpYWJsZXMgYWJvdXQgdXNhZ2Ugb2YgYnJhbmRzIGFuZCBzcGVjaWZpYyBmbGF2b3JzIG9mIGUtY2lnYXJldHRlcywgYmVjYXVzZSBhbHRob3VnaCBsYXRlciB5ZWFycyBoYXZlIHF1ZXN0aW9ucyBhYm91dCB0aGlzLCB0aGlzIHllYXIgdW5mb3J0dW5hdGVseSBvbmx5IGhhcyBicm9hZCBxdWVzdGlvbnMgYWJvdXQgZmxhdm9ycy4gRXZlbnR1YWxseSB3ZSB3YW50IHRvIHB1dCB0aGUgZGF0YSBmcm9tIGVhY2ggeWVhciB0b2dldGhlciwgc28gd2UgbmVlZCB0aGUgc2FtZSB2YXJpYWJsZXMgZm9yIGVhY2ggeWVhci4gVGh1cyB3ZSBuZWVkIHRvIGFkZCB2YXJpYWJsZXMgZm9yIGJyYW5kIGFuZCBmbGF2b3IgdG8gdGhlIDIwMTUgZGF0YSBzZXQgdGhhdCBqdXN0IGNvbnRhaW4gbWlzc2luZyB2YWx1ZXMgKGBOQWApLgoKVG8gY3JlYXRlIHRoZXNlIG5ldyB2YXJpYWJsZXMsIHdlIHdpbGwgdXNlIHRoZSBgbXV0YXRlYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBUaGUgYG11dGF0ZWAgZnVuY3Rpb24gY2FuIGFsc28gYmUgdXNlZCB0byBjaGFuZ2UgdGhlIGV4aXN0aW5nIHZhcmlhYmxlcyBhbmQgY3JlYXRlIG5ldyB2YXJpYWJsZXMgZnJvbSB0aGUgb2xkIG9uZXMuCgpgYGB7cn0Kbnl0c19kYXRhW1sibnl0czIwMTUiXV0gPC0gbnl0c19kYXRhW1sibnl0czIwMTUiXV0gJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgICAgICAgICBicmFuZF9lY2lnPU5BLAogICAgICAgICAgIG1lbnRob2w9TkEsCiAgICAgICAgICAgY2xvdmVfc3BpY2U9TkEsCiAgICAgICAgICAgZnJ1aXQ9TkEsCiAgICAgICAgICAgY2hvY29sYXRlPU5BLAogICAgICAgICAgIGFsY29ob2xpY19kcmluaz1OQSwKICAgICAgICAgICBjYW5keV9kZXNzZXJ0X3N3ZWV0cz1OQSwKICAgICAgICAgICBvdGhlcj1OQSwKICAgICAgICAgICBub191c2U9TkEpIApgYGAKCgpOb3cgd2UgY2FuIHNlZSBob3cgdGhlIGRhdGEgaGFzIGNoYW5nZWQ6CgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQpnbGltcHNlKG55dHNfZGF0YVtbIm55dHMyMDE1Il1dKQpgYGAKIyMjIwoKClRoZSBkYXRhIGZvciAyMDE2LTIwMTggaGF2ZSBtYW55IGNvbW1vbiBhdHRyaWJ1dGVzLCBzbyB3ZSB3aWxsIHdhbnQgdG8gd3JpdGUgY29kZSB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGFsbCB0aHJlZSBkYXRhIHNldHMuIFRvIGRvIHRoaXMsIHdlIHdpbGwgdXNlIGEgYGZ1bmN0aW9uYCBpbiBSLCB3aGljaCBpcyBiYXNpY2FsbHkgYSBwaWVjZSBvZiBjb2RlIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gc2ltaWxhciBidXQgZGlmZmVyZW50IG9iamVjdHMgaW4gUiAoZS5nLiwgdGhlIGRhdGEgdGliYmxlcyBmcm9tIGVhY2ggb2YgdGhlc2UgdGhyZWUgeWVhcnMpLiBGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBmdW5jdGlvbnMsIHNlZSBmb3IgZXhhbXBsZSBbaGVyZV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9mdW5jdGlvbnMuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifS4KCkFWT0NBRE86IEkgYWRkZWQgYSBsaW5rIHRvIHRoZSByNGRzIGNoYXB0ZXIgb24gZnVuY3Rpb25zOyBhcmUgdGhlcmUgb3RoZXIgcGxhY2VzIGluIHRoZSBjYXNlIHN0dWRpZXMgdGhhdCB3ZSBkaXNjdXNzIGZ1bmN0aW9ucz8gT3IgYWRkaXRpb25hbCBsaW5rcyBvciByZXNvdXJjZXMgeW91IHdhbnQgdG8gYWRkPwoKClRoZXNlIG5leHQgMyB5ZWFycyBoYXZlIHRoZSBzYW1lIHN0cnVjdHVyZSBmb3IgbWFueSBvZiB0aGUgcXVlc3Rpb25zIHdlIGFyZSBpbnRlcmVzdGVkIGluLiBGb3IgZXhhbXBsZSwgdGhleSBhbGwgaGF2ZSBmbGF2b3IgcXVlc3Rpb25zLCBidXQgbm90IGEgYnJhbmQgcXVlc3Rpb24uIE1vcmVvdmVyLCB0aGVpciB2YXJpYWJsZSBuYW1lcyBhcmUgY29uc2lzdGVudCBhY3Jvc3MgdGhlIHllYXJzOyBmb3IgZWFjaCB5ZWFyLCB3ZSB3YW50IHRvIHJlcGxhY2UgdGhlIHZhZ3VlIHF1ZXN0aW9uIG5hbWUgYFE1MEFgIHdpdGggdGhlIHZhbHVlIGBtZW50aG9sYCBpbiBhbGwgdGhyZWUgZGF0YSBzZXRzLCBhbmQgdGhlIHNhbWUgaXMgdHJ1ZSBmb3IgdGhlIG90aGVyIGZsYXZvciB2YXJpYWJsZXMuICBGb3IgZWFjaCBvZiB0aGVzZSB5ZWFycywgd2UgYWxzbyB3YW50IHRvIGNyZWF0ZSBhIHZhcmlhYmxlIGBicmFuZF9lY2lnYCB0aGF0IGp1c3QgY29udGFpbnMgYE5BYCB2YWx1ZXMuICAKClNpbmNlIHdlIHdhbnQgdG8gcGVyZm9ybSB0aGUgc2FtZSBtb2RpZmljYXRpb25zIG9uIHRoZSBkYXRhIGZyb20gYWxsIHRocmVlIHllYXJzLCByYXRoZXIgdGhhbiByZXBlYXRpbmcgdGhlIHNhbWUgc29tZXdoYXQgbWVzc3kgcGllY2Ugb2YgY29kZSB0aHJlZSB0aW1lcywgd2UgY2FuIGRvIHRoaXMgbW9yZSBlZmZpY2llbnRseSBpZiB3ZSBjcmVhdGUgYSBmdW5jdGlvbiB0byBkbyBhbGwgb2YgdGhlc2Ugc3RlcHMgYXQgb25jZS4gVGhlbiB3ZSBjYW4gdXNlIHRoZSBgbWFwX2F0KClgIGZ1bmN0aW9uIG9mIHRoZSBgcHVycnJgIHBhY2thZ2UgdG8gYXBwbHkgdGhlIGZ1bmN0aW9uIHdlIGNyZWF0ZWQgKGZvciByZW5hbWluZyB2YXJpYWJsZXMgZXRjLikgdG8gdGhlIGRhdGEgZnJvbSAyMDE2LTIwMTguIEJ5IHVzaW5nIGB2YXJzKClgIGluc2lkZSBvZiB0aGUgYG1hcF9hdCgpYCBmdW5jdGlvbiB3ZSBjYW4gc3BlY2lmeSB3aGF0IHRpYmJsZXMgd2l0aGluIG91ciBgbnl0c19kYXRhYCBsaXN0IHdlIHdhbnQgdG8gaW5jbHVkZSBvciBleGNsdWRlLgoKYGBge3J9CgpVcGRhdGVfc3VydmV5IDwtIGZ1bmN0aW9uKHgpIHsgeCAlPiUKICAgICAgcmVuYW1lKEFnZT1RMSwKICAgICAgICAgICBTZXg9UTIsCiAgICAgICAgICAgR3JhZGU9UTMsCiAgICAgICAgICAgbWVudGhvbD1RNTBBLAogICAgICAgICAgIGNsb3ZlX3NwaWNlPVE1MEIsCiAgICAgICAgICAgZnJ1aXQ9UTUwQywKICAgICAgICAgICBjaG9jb2xhdGU9UTUwRCwKICAgICAgICAgICBhbGNvaG9saWNfZHJpbms9UTUwRSwKICAgICAgICAgICBjYW5keV9kZXNzZXJ0X3N3ZWV0cz1RNTBGLAogICAgICAgICAgIG90aGVyPVE1MEcsCiAgICAgICAgICAgbm9fdXNlPVE1MEgpICU+JQogICAgbXV0YXRlKGJyYW5kX2VjaWc9TkEpCn0KCiNmZXcgb3B0aW9ucyB0byBhcHBseSB0byB0aGUgZGF0YToKI255dHNfZGF0YSA8LW55dHNfZGF0YSAlPiUgbWFwX2F0KHZhcnMobnl0czIwMTYsIG55dHMyMDE3LCBueXRzMjAxOCksIFVwZGF0ZV9zdXJ2ZXkpCiNueXRzX2RhdGEgPC1ueXRzX2RhdGEgJT4lIG1hcF9hdChjKCJueXRzMjAxNiIsICJueXRzMjAxNyIsICJueXRzMjAxOCIpLCBVcGRhdGVfc3VydmV5KQpueXRzX2RhdGEgPC1ueXRzX2RhdGEgJT4lIG1hcF9hdCh2YXJzKC1ueXRzMjAxNSwgLW55dHMyMDE5KSwgVXBkYXRlX3N1cnZleSkKYGBgCgpUaGUgZmluYWwgeWVhciwgMjAxOSwgaGFzIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGRhdGEgc3RydWN0dXJlIGNvbXBhcmVkIHRvIHRoZXNlIGVhcmxpZXIgZGF0YSBzZXRzLiBGb3IgZXhhbXBsZSwgaXQgYWN0dWFsbHkgaGFzIGEgYGJyYW5kX2VjaWdgIHZhcmlhYmxlIGFscmVhZHksIGJ1dCBkb2VzIG5vdCBjb250YWluIGEgYG5vX3VzZWAgdmFyaWFibGUuIFNvIHdlIGNhbid0IHVzZSB0aGUgc2FtZSBmdW5jdGlvbiBmb3IgdGhpcyBkYXRhIHNldCwgYnV0IGhhdmUgdG8gd3JpdGUgYW4gaW5kaXZpZHVhbCBjb2RlIGNodW5rLgoKYGBge3J9Cm55dHNfZGF0YVtbIm55dHMyMDE5Il1dIDwtIG55dHNfZGF0YVtbIm55dHMyMDE5Il1dICU+JQogICAgcmVuYW1lKGJyYW5kX2VjaWc9UTQwLAogICAgICAgICAgIEFnZT1RMSwKICAgICAgICAgICBTZXg9UTIsCiAgICAgICAgICAgR3JhZGU9UTMsCiAgICAgICAgICAgbWVudGhvbD1RNjJBLAogICAgICAgICAgIGNsb3ZlX3NwaWNlPVE2MkIsCiAgICAgICAgICAgZnJ1aXQ9UTYyQywKICAgICAgICAgICBjaG9jb2xhdGU9UTYyRCwKICAgICAgICAgICBhbGNvaG9saWNfZHJpbms9UTYyRSwKICAgICAgICAgICBjYW5keV9kZXNzZXJ0X3N3ZWV0cz1RNjJGLAogICAgICAgICAgIG90aGVyPVE2MkcpICU+JQogICAgbXV0YXRlKG5vX3VzZT0ibWlzc2luZyIpCmBgYAoKCk5vdyBsZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgdmFyaWFibGUgbmFtZXMgZm9yIGVhY2ggb2YgdGhlIHllYXJzIHVzaW5nIHRoZSBgbWFwYCBmdW5jdGlvbiBmcm9tIGBwdXJycmAuCgojIyMjIHsuc2Nyb2xsYWJsZSB9CgpgYGB7cn0KbWFwKG55dHNfZGF0YSwgbmFtZXMpCmBgYAojIyMjCgpJdCdzIGxvb2tpbmcgYmV0dGVyISBUaGVyZSBhcmUgc3RpbGwgc29tZSBkaWZmZXJlbmNlcyBpbiB0aGUgc2V0IG9mIHZhcmlhYmxlcyBpbiB0aGUgZGlmZmVyZW50IHllYXJzLCBidXQgdGhpbmdzIGFyZSBtdWNoIGNsb3Nlci4KCiMjIyBVcGRhdGluZyBWYWx1ZXMKCk5vdyB0aGF0IHdlIGhhdmUgbWFkZSBzb21lIHByb2dyZXNzIG9uIHRoZSBzZWxlY3Rpb24gYW5kIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgdGhlbXNlbHZlcywgd2Ugd2lsbCB3b3JrIG9uIHRoZSB2YWx1ZXMgY29udGFpbmVkIGluIHRoZSBkaWZmZXJlbnQgdmFyaWFibGVzLgoKV2UgY2FuIHN0YXJ0IHdpdGggdXBkYXRpbmcgdGhlIHZhbHVlcyBmb3IgYEFnZWAgYW5kIGBHcmFkZWAsIHNvIHRoYXQgdGhleSBhcmUgbW9yZSB1bmRlcnN0YW5kYWJsZS4gCgpSZWNhbGwgZnJvbSB0aGUgY29kZWJvb2sgZm9yIHRoaXMgeWVhcidzIGRhdGEgc2V0IHRoYXQgYEFnZWAgaXNuJ3QgbGlzdGVkIGluIHRoZSB3YXkgb25lIG1pZ2h0IGV4cGVjdCwgaS5lLiwgaXQgaXMgbm90IGp1c3QgYSBudW1iZXIgb2YgeWVhcnMsIGJ1dCBhIG51bWVyaWNhbGx5IHZhbHVlZCBjYXRlZ29yaWNhbCB2YXJpYWJsZS4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbiA9ImNlbnRlciIsIG91dC53aWR0aCA9ICI2MDAgcHgifQoKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInFuMS5wbmciKSkKYGBgCgpUaGUgc2FtZSBpcyB0cnVlIGZvciBgR3JhZGVgOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIiwgb3V0LndpZHRoID0gIjYwMCBweCJ9Cgprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiZ3JhZGUucG5nIikpCmBgYAoKKipUaGlzIGlzIHdoeSBpdCBpcyBzbyBpbXBvcnRhbnQgdG8gYWx3YXlzIGNoZWNrIHRoZSBjb2RlYm9vayEhKioKCldlIGFsc28gIHdhbnQgdG8gcmVwbGFjZSB0aGUgdmFsdWUgb2YgYDE5YCBmb3IgYEFnZWAgdG8gYmUgYCI+MTgiYCBhbmQgdGhlIHZhbHVlIG9mIGAxM2AgZm9yIGBHcmFkZWAgdG8gYmUgcmVwbGFjZWQgd2l0aCBgIlVuZ3JhZGVkL090aGVyImAgQWxzbyBhY2NvcmRpbmcgdG8gdGhlIGNvZGVib29rcywgbnVtZXJpYyB2YWx1ZXMgb2YgYDFgIGluZGljYXRlIGEgc3VydmV5IGFuc3dlciBvZiBgRkFMU0VgLCB3aGlsZSBhIHZhbHVlIG9mIGAyYCBpbmRpY2F0ZXMgYFRSVUVgLiBgU2V4YCBuZWVkcyB0byBiZSByZWNvZGVkLCBidXQgaXQgaXMgYSBiaXQgdW5jbGVhciBpZiBpdCBpcyBlbmNvZGVkIHNsaWdodGx5IGRpZmZlcmVudGx5IGFjcm9zcyB5ZWFycy4KCkFWT0NBRE86IEZvciB0aGUgU2V4IHZhcmlhYmxlLCBob3cgZGlkIHlvdSBkZXRlcm1pbmUgIkl0J3MgYSBiaXQgZGlmZmljdWx0IHRvIHRlbGwgaWYgdGhlIGVuY29kaW5nIHdhcyB0aGUgc2FtZSBhY3Jvc3MgeWVhcnMiIC0tIEkgZG9uJ3Qgc2VlIGRvY3VtZW50YXRpb24gb2YgdGhpcyAoaS5lLiwgaXMgdGhpcyBtaXNzaW5nIGZyb20gdGhlIGNvZGVib29rIHNvbWVob3c/KSwgc28gaXQgbWlnaHQgYmUgaGVscGZ1bCB0byBsZXQgdGhlIHJlYWRlciBrbm93IGhvdyB5b3UgZmlndXJlZCB0aGlzIG91dC4gQ2FycmllIHNheXMgdG8gbG9vayBhdCB0aGUgY29kZWJvb2tzIGFuZCBpdCB3aWxsIG1ha2Ugc2Vuc2U7IGNvdWxkIGNvbnNpZGVyIHNjcmVlbiBzaG90cy4gSSBsb29rZWQgYXQgaXQgYWdhaW47IHRoZSBjb25mdXNpb24gc2VlbXMgdG8gY29tZSBmcm9tIHRoZSBTRVg6UkVDT0RFIHZhcmlhYmxlcywgYnV0IHdlIGFyZW4ndCB1c2luZyB0aG9zZS4gT3RoZXJ3aXNlLCBJIGRvIHRoaW5rIHRoaXMgY291bGQgYmUgZHJvcHBlZC4KCgpMZXQncyBjcmVhdGUgYSBmdW5jdGlvbiB0byBtYWtlIGFsbCB0aGVzZSB1cGRhdGVzIGV4Y2VwdCBmb3IgYFNleGAuIFdlIHdpbGwgdXNlIHRoZSBgbXV0YXRlYCBmdW5jdGlvbiBhZ2FpbiwgYXMgd2VsbCBhcyBgbXV0YXRlX2FsbGAgYW5kIGByZWNvZGVgIHRvIHJlcGxhY2Ugc3BlY2lmaWMgdmFsdWVzIG9mIGNlcnRhaW4gdmFyaWFibGVzLgoKYGBge3J9ClVwZGF0ZV92YWx1ZXMgPC0gZnVuY3Rpb24oeCkgeyB4ICU+JQogICAgICBtdXRhdGUoQWdlPWFzLm51bWVyaWMoQWdlKSs4LAogICAgICAgICAgICAgR3JhZGU9YXMubnVtZXJpYyhHcmFkZSkrNSklPiUKICAgICAgbXV0YXRlKEFnZT1hcy5mYWN0b3IoQWdlKSwKICAgICAgICAgR3JhZGU9YXMuZmFjdG9yKEdyYWRlKSwKICAgICAgICAgKSAlPiUKICBtdXRhdGVfYWxsKH4gcmVwbGFjZSguLCAuICVpbiUgYygiKiIsICIqKiIpLCBOQSkpJT4lCiAgbXV0YXRlKEFnZT1yZWNvZGUoQWdlLAogICAgICAgICAgICAgICAgICAgIGAxOWAgPSAiPjE4IiwKICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBHcmFkZT1yZWNvZGUoR3JhZGUsCiAgICAgICAgICAgICAgICAgICAgICBgMTNgID0gIlVuZ3JhZGVkL090aGVyIikpICU+JQogIG11dGF0ZV9hdCh2YXJzKHN0YXJ0c193aXRoKCJFIiwgaWdub3JlLmNhc2UgPSBGQUxTRSksCiAgICAgICAgICAgICAgICAgICBzdGFydHNfd2l0aCgiQyIsIGlnbm9yZS5jYXNlID0gRkFMU0UpKSwKICAgICAgICAgICAgICBsaXN0KH5yZWNvZGUoLiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYDFgID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYDJgID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC5taXNzaW5nID0gTkEpKSkKfQoKbnl0c19kYXRhIDwtbnl0c19kYXRhICU+JSBtYXAoLixVcGRhdGVfdmFsdWVzKQoKYGBgCgoKTm93IGxldCdzIHVwZGF0ZSB0aGUgYFNleGAgZW5jb2Rpbmc6CgpJdCdzIGEgYml0IGRpZmZpY3VsdCB0byB0ZWxsIGlmIHRoZSBlbmNvZGluZyB3YXMgdGhlIHNhbWUgYWNyb3NzIHllYXJzLCBzbyBsZXQncyBjaGVjayB1c2luZyB0aGUgYGNvdW50KClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuCgpBY2NvcmRpbmcgdG8gdGhlIGNvZGVib29rLCB3ZSBzaG91bGQgaGF2ZTogIAoxKSA4LDk1OCBtYWxlcyBpbiAyMDE1IAoyKSAxMCw0MzggbWFsZXMgaW4gMjAxNiAKMykgOCw4ODEgbWFsZXMgaW4gMjAxNyAgCjQpIDEwLDA2OSBtYWxlcyBpbiAyMDE4ICAKNSkgOSw4MDMgbWFsZXMgaW4gMjAxOSAgCgpgYGB7cn0KY291bnRfc2V4IDwtZnVuY3Rpb24oeCl7eCAlPiVjb3VudChTZXgpfQpueXRzX2RhdGEgJT4lIG1hcCguLCBjb3VudF9zZXgpCmBgYAoKClRodXMsIGl0IGxvb2tzIGxpa2UgbWFsZXMgd2VyZSBlbmNvZGVkIGFzIGAxYCBmb3IgZWFjaCB5ZWFyLgoKMSkgOCw5NTggbWFsZXMgaW4gMjAxNSB3aGVyZSAxID0gbWFsZSAgCjIpIDEwLDQzOCBtYWxlcyBpbiAyMDE2IHdoZXJlIDEgPSBtYWxlCjMpIDgsODgxIG1hbGVzIGluIDIwMTcgd2hlcmUgMSA9IG1hbGUgIAo0KSAxMCwwNjkgbWFsZXMgaW4gMjAxOCB3aGVyZSAxID0gbWFsZQo1KSA5LDgwMyBtYWxlcyBpbiAyMDE5IHdoZXJlIDEgPSBtYWxlCgoKYGBge3J9CgogIFVwZGF0ZV9zZXggPC0gZnVuY3Rpb24oeCl7eCAlPiUKICAgICAgbXV0YXRlKFNleCA9IGFzLmZhY3RvcihTZXgpKSAlPiUKICAgICAgICAgbXV0YXRlKFNleCA9IHJlY29kZShTZXgsCiAgICAgICAgICAgICAgICAgICAgICBgMWA9ICJtYWxlIiwKICAgICAgICAgICAgICAgICAgICAgIGAyYCA9ICJmZW1hbGUiKSkKICB9CgpueXRzX2RhdGEgPC1ueXRzX2RhdGEgJT4lIG1hcCguLCBVcGRhdGVfc2V4KQpjb3VudF9zZXggPC1mdW5jdGlvbih4KXt4ICU+JWNvdW50KFNleCl9Cm55dHNfZGF0YSAlPiUgbWFwKC4sIGNvdW50X3NleCkKCmBgYAoKTG9va3MgZ29vZCEKCgoKVGhlIHllYXJzICgyMDE2LTIwMTkpIHRoYXQgaGF2ZSBmbGF2b3JzIGFsc28gbmVlZCB0aGUgZmxhdm9yIGRhdGEgdG8gYmUgbG9naWNhbCAobWVhbmluZyBUUlVFIG9yIEZBTFNFKToKCmBgYHtyfQpVcGRhdGVfZmxhdm9ycyA8LSBmdW5jdGlvbih4KXt4ICU+JQogICBtdXRhdGVfYXQodmFycyhtZW50aG9sOm5vX3VzZSksCiAgICAgICAgICAgICAgbGlzdCh+cmVjb2RlKC4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGAxYCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIC5taXNzaW5nID0gRkFMU0UpKSkgfQoKbnl0c19kYXRhICA8LSBueXRzX2RhdGEgICU+JSBtYXBfYXQodmFycygtbnl0czIwMTUpLCBVcGRhdGVfZmxhdm9ycykKCmBgYAoKCk5vdyB0aGVyZSBhcmUganVzdCBhIGZldyBjaGFuZ2VzIG5lZWRlZCB0aGF0IGFyZSBzcGVjaWZpYyB0byAyMDE5LiBTcGVjaWZpY2FsbHksIHNvbWUgb2YgdGhlIDIwMTkgcXVlc3Rpb25zIHVzZSB0aGUgdmFsdWVzICIuTiIsICIuUyIsIGFuZCAiLloiIHRvIGluZGljYXRlIGRpZmZlcmVudCB0eXBlcyBvZiBtaXNzaW5nIGRhdGEgKHNlZSBmb3IgZXhhbXBsZSBRMiBvZiB0aGUgMjAxOSBbY29kZWJvb2tdKC4vZG9jcy8yMDE5LW55dHMtZGF0YXNldC1hbmQtY29kZWJvb2stbWljcm9zb2Z0LWV4Y2VsLzIwMTktbnl0cy1jb2RlYm9vay1wLnBkZil7dGFyZ2V0PSJfYmxhbmsifSk7IHdlIGp1c3Qgd2FudCB0aGVtIHRvIGJlIHJlcGxhY2VkIHdpdGggYE5BYCB2YWx1ZXMuCgoKYGBge3J9Cm55dHNfZGF0YVtbIm55dHMyMDE5Il1dIDwtIG55dHNfZGF0YVtbIm55dHMyMDE5Il1dICU+JQogIG11dGF0ZV9hbGwofiByZXBsYWNlKC4sIC4gJWluJSBjKCIuTiIsIi5TIiwiLloiKSwgTkEpKSAlPiUKICBtdXRhdGUocHN1PWFzLmNoYXJhY3Rlcihwc3UpKSAlPiUKICBtdXRhdGUoYnJhbmRfZWNpZyA9IHJlY29kZShicmFuZF9lY2lnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMWAgPSAiT3RoZXIiLCAjbGV2ZWxzIDEsOCBjb21iaW5lZCB0byBgT3RoZXJgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMmAgPSAiQmx1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDNgID0gIkpVVUwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgNGAgPSAiTG9naWMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgNWAgPSAiTWFya1RlbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGA2YCA9ICJOSk9ZIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDdgID0gIlZ1c2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgOGAgPSAiT3RoZXIiKSkKCmBgYAoKR3JlYXQhIE5vdyBvdXIgdmFsdWVzIGRvbid0IG5lZWQgdG8gYmUgaGFuZGxlZCBhbnkgZGlmZmVyZW50bHkgZm9yIGFueSBvZiB0aGUgeWVhcnMsIHRodXMgd2UgY2FuIGNvbWJpbmUgdGhlIGRhdGEgYWNyb3NzIHllYXJzLgoKRXZlbiB0aG91Z2ggd2UgaGF2ZSBkaWZmZXJlbnQgbnVtYmVycyBvZiB2YXJpYWJsZXMgZm9yIGVhY2ggeWVhciwgd2UgY2FuIGNvZXJjZSB0aGUgZGF0YSB0byBiZSBjb21iaW5lZCBpbnRvIG9uZSB0aWJibGUgYnkgdXNpbmcgdGhlIGBiaW5kX3Jvd3MoKWAgZnVuY3Rpb24gb2YgYGRwbHlyYC4gSW1wb3J0YW50bHksIHRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmVxdWlyZSB0aGF0IHRoZSBjb2x1bW5zIGJlIHRoZSBzYW1lLiAgVGhpcyB3aWxsIGNyZWF0ZSBOQSB2YWx1ZXMgZm9yIGFueSB2YXJpYWJsZSB0aGF0IGlzIG5vdCBwcmVzZW50IGluIGdpdmVuIGRhdGEgZnJhbWUgYnV0IGlzICBwcmVzZW50IGluIG9uZSBvZiB0aGUgb3RoZXIgZGF0YSBmcmFtZXMgdGhhdCBpcyBiZWluZyBjb21iaW5lZC4gTm90ZSB0aGF0IHRoZSBgYmluZF9jb2xzKClgIGZ1bmN0aW9uIGRvZXMgZXhwZWN0IHRoYXQgdGhlIHJvd3MgbWF0Y2guIFRoZSBgLmlkYCBhcmd1bWVudCB3aWxsIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSB3aXRoIHZhbHVlcyB0byBsaW5rIGVhY2ggcm93IHRvIGl0cyBvcmlnaW5hbCBkYXRhIGZyYW1lLiBGb3IgbW9yZSBpbmZvcm1hdGlvbiBzZWUgW2hlcmVdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvYmluZC5odG1sKS4KCgpgYGB7cn0Kbnl0c19kYXRhIDwtIG55dHNfZGF0YSAlPiUKICBtYXBfZGYoYmluZF9yb3dzLCAuaWQgPSAieWVhciIpCgpnbGltcHNlKG55dHNfZGF0YSkKYGBgCgpXZSB3aWxsIHdhbnQgdG8gZG8gc29tZSBvZiBvdXIgYW5hbHlzaXMgc3BsaXQgYnkgeWVhciwgc28gd2Ugd291bGQgbGlrZSB0byBiZSBzdXJlIHdlIGhhdmUgb25lIHZhcmlhYmxlIHRoYXQgaGFzIHRoZSBjb3JyZWN0IHZhbHVlIGZvciB5ZWFyLiBJdCBsb29rcyBsaWtlIHdlIGp1c3QgbmVlZCB0byByZW1vdmUgYCJueXRzImAgZnJvbSB0aGUgeWVhciB2YXJpYWJsZSB0aGF0IHdlIGNyZWF0ZWQgZnJvbSB0aGUgbmFtZXMgb2YgdGhlIHRpYmJsZXMgaW4gb3VyIGxpc3QgYW5kIHdlIHNob3VsZCBiZSBhbGwgc2V0LiBXZSB3aWxsIHVzZSBhbm90aGVyIGZ1bmN0aW9uIGZyb20gdGhlIGBzdHJpbmdyYCBwYWNrYWdlIHRvIGRvIHRoaXMuIFRoZSBgc3RyX3JlbW92ZSgpYCBmdW5jdGlvbiB0YWtlcyBhIHN0cmluZyBmb2xsb3dlZCBieSBhIHBhdHRlcm4gYW5kIHJlbW92ZXMgdGhlIHBhdHRlcm4gZnJvbSB0aGUgc3RyaW5nLgoKYGBge3J9Cm55dHNfZGF0YSA8LSBueXRzX2RhdGEgJT4lCiAgbXV0YXRlKHllYXI9YXMubnVtZXJpYyhzdHJfcmVtb3ZlKHllYXIsIm55dHMiKSkpCgpgYGAKCkhlcmUgaXMgb3VyIGNsZWFuIGFuZCB3cmFuZ2xlZCBkYXRhOgoKIyMjIyB7LnNjcm9sbGFibGV9CmBgYHtyfQpnbGltcHNlKG55dHNfZGF0YSkKCmBgYAoKIyMjIwoKCk5vdGUgdGhhdCB0aGVyZSBhcmUgc2V2ZXJhbCB2YXJpYWJsZXMgd2hlcmUgdGhlcmUgYXJlIHNpbWlsYXIgbmFtZXMsIGJ1dCB3aXRoIGEgYENgIGNvbXBhcmVkIHRvIGFuIGBFYCBpbiB0aGUgdmFyaWFibGUgbmFtZS4gVGhvc2Ugc3RhcnRpbmcgd2l0aCBgQ2AgYXJlIHJlbGF0ZWQgdG8gcXVlc3Rpb25zIGFib3V0IGN1cnJlbnQgdXNhZ2UgKGxhc3QgMzAgZGF5cyksIHdoaWxlIHRob3NlIHdpdGggYW4gYEVgIGFyZSByZWxhdGVkIHRvIHVzYWdlIGFjcm9zcyB0aGUgc3ViamVjdHMgd2hvbGUgbGlmZSAoImV2ZXIiIHVzYWdlKS4gV2Ugd2lsbCBkaXNjdXNzIHRoZXNlIGdyb3VwcyBmdXJ0aGVyIGJlbG93LgoKQVZPQ0FETzogSSdtIG5vdCBzdXJlIHdoZXJlIHRoaXMgc2hvdWxkIGdvLCBidXQgSSBoYWQgdGhlIHRob3VnaHQgc28gSSBmaWd1cmVkIEknZCBpbmNsdWRlIGl0LiBNYXliZSB3ZSBjYW4gYmUgbW9yZSBjb25zaXN0ZW50IGFib3V0IGhvdyB3ZSByZWZlciB0byBzdHVkZW50cywgc3ViamVjdHMsIHJlc3BvbmRlbnRzPyBDYXJyaWUgc3VnZ2VzdHMgbWF5YmUgdHJ5aW5nIHRvIHVzZSBzdHVkZW50cyB3aGVyZSB3ZSBhcmUgdGFsa2luZyBhYm91dCB0aGlzIHNwZWNpZmljIGRhdGEgc2V0LCBidXQgcmVzcG9uZGVudHMgaW4gdGhlIGdlbmVyYWwgc3VydmV5IHdlaWdodGluZyBzZWN0aW9uLgoKCgojIyMgVmFyaWFibGUgVGFibGUKPGRldGFpbHM+PHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gc2VlIGEgdGFibGUgYWJvdXQgdGhlIGZpbmFsIHZhcmlhYmxlcyBpbiBvdXIgZGF0YSBzZXQuIDwvc3VtbWFyeT4KCnZhbHVlIDEgPSB5ZXMsIHZhbHVlIDIgPSBubwoKVmFyaWFibGUgICB8IERldGFpbHMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQoqKnllYXIqKiAgfCB0aGUgeWVhciB0aGF0IHRoZSBzdXJ2ZXkgcmVzdWx0cyBmcm9tIGEgcGFydGljdWxhciBzdHVkZW50IHdlcmUgYWNxdWlyZWQgIAoqKnBzdSoqIHwgdGhlIHByaW1hcnkgc2FtcGxpbmcgdW5pdCBmb3IgdGhlIHN1cnZleSB3ZWlnaHRpbmcgIAoqKmZpbndndCoqIHwgdGhlIGZpbmFsIGFuYWx5c2lzIHdlaWdodCBmb3IgdGhlIHN1cnZleSB3ZWlnaHRpbmcgIAoqKnN0cmF0dW0qKiB8IHRoZSBzdHJhdHVtIHVzZWQgZm9yIHZhcmlhbmNlIGVzdGltYXRpb24gZm9yIHRoZSBzdXJ2ZXkgd2VpZ2h0aW5nICAKKipBZ2UqKiB8IHRoZSBhZ2Ugb2YgdGhlIHN0dWRlbnQgd2hlbiB0aGV5IHRvb2sgdGhlIHN1cnZleSAgCioqU2V4KiogfCB0aGUgc2V4IG9mIHRoZSBzdHVkZW50IHdoZW4gdGhleSB0b29rIHRoZSBzdXJ2ZXkgIAoqKkdyYWRlKiogfCB0aGUgZ3JhZGUgb2YgdGhlIHRoZSBzdHVkZW50IHdoZW4gdGhlIHRvb2sgdGhlIHN1cnZleSAgCioqRUNJR1QqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgaGF2aW5nIGV2ZXIgdHJpZWQgY2lnYXJldHRlIHNtb2tpbmcsIGV2ZW4gb25lIG9yIHR3byBwdWZmcyAgCioqRUNJR0FSKiogfCBzdHVkZW50IHJlcG9ydGVkIGhhdmluZyBldmVyIHRyaWVkIGNpZ2FyLCBjaWdhcmlsbG8sIG9yIGxpdHRsZSBjaWdhciBzbW9raW5nLCBldmVuIG9uZSBvciB0d28gcHVmZnMgIAoqKkVTTFQqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgaGF2aW5nIGV2ZXIgdHJpZWQgY2hld2luZyB0b2JhY2NvLCBzbnVmZiwgb3IgZGlwICAKKipFRUxDSUdUKiogfCBzdHVkZW50IHJlcG9ydGVkIGhhdmluZyBldmVyIHRyaWVkIGUtY2lnYXJldHRlcyAgCioqRVJPTExDSUdUUyoqIHwgc3R1ZGVudCByZXBvcnRlZCBoYXZpbmcgZXZlciB0cmllZCByb2xsLXlvdXItb3duIGNpZ2FyZXR0ZXMgIAoqKkVGTEFWQ0lHVFMqKiB8ICAoMjAxNSBvbmx5KSBiYXNlZCBvbiBhbnN3ZXIgdG8gIldoaWNoIG9mIHRoZSBmb2xsb3dpbmcgdG9iYWNjbyBwcm9kdWN0cyB0aGF0IHlvdSB1c2VkIGluIHRoZSBwYXN0IDMwIGRheXMgd2VyZSBmbGF2b3JlZD8iICAKKipFQklESVMqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgaGF2aW5nIGV2ZXIgdHJpZWQgYmlkaXMgKHNtYWxsIGJyb3duIGNpZ2FyZXR0ZXMgd3JhcHBlZCBpbiBhIGxlYWYpICAKKipFRkxBVkNJR0FSKiogfCBzdHVkZW50IHJlcG9ydGVkIGhhdmluZyBldmVyIHRyaWVkIGEgZmxhdm9yZWQgY2lnYXIgKDIwMTUtMjAxNikKKipFSE9PS0FIKiogfCBzdHVkZW50IHJlcG9ydGVkIGhhdmluZyBldmVyIHNtb2tlZCB0b2JhY2NvIGZyb20gYSBob29rYWggb3IgYSB3YXRlcnBpcGUgIAoqKkVQSVBFKiogfCBzdHVkZW50IHJlcG9ydGVkIGhhdmluZyBldmVyIHNtb2tlZCB0b2JhY2NvIGZyb20gYSBwaXBlIChub3QgaG9va2FoKSAgCioqRVNOVVMqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgaGF2aW5nIGV2ZXIgdXNlZCBzbnVzLCBzdWNoIGFzIENhbWVsIG9yIE1hbGJvcm8gU251cyAgCioqRURJU1NPTFYqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgaGF2aW5nIGV2ZXIgdHJpZWQgZGlzc29sdmFibGUgdG9iYWNjbyBwcm9kdWN0cyBzdWNoIGFzIEFyaXZhLCBTdG9uZXdhbGwsIENhbWVsIG9yYnMsIENhbWVsIHN0aWNrcywgTWFybGJvcm8gc3RpY2tzLCBvciBDYW1lbCBzdHJpcHMgIAoqKkNDSUdUKiogfCBzdHVkZW50IHJlcG9ydGVkIHRoZXkgc21va2VkIGNpZ2FyZXR0ZXMgb24gPj0gMSBvZiB0aGUgcGFzdCAzMCBkYXlzICAKKipDQ0lHQVIqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgdGhleSBzbW9rZWQgY2lnYXJzIG9uID49IDEgb2YgdGhlIHBhc3QgMzAgZGF5cyAgCioqQ1NMVCoqIHwgc3R1ZGVudCByZXBvcnRlZCB0aGV5IHVzZWQgY2hld2luZyB0b2JhY2NvLCBzbnVmZiwgb3IgZGlwIG9uID49IDEgb2YgdGhlIHBhc3QgMzAgZGF5cyAgCioqQ0VMQ0lHVCoqIHwgc3R1ZGVudCByZXBvcnRlZCB0aGV5IHVzZWQgZWxlY3Ryb25pYyBjaWdhcmV0dGVzIG9yIGUtY2lnYXJldHRlcyBvbmUgb3IgbW9yZSBkYXlzIGluIHRoZSBwYXN0IDMwCioqQ1JPTExDSUdUUyoqIHwgc3R1ZGVudCByZXBvcnRlZCB0aGV5IHNtb2tlZCByb2xsLXlvdXItb3duIGNpZ2FyZXR0ZXMgZHVyaW5nIHRoZSBwYXN0IDMwIGRheXMgIAoqKkNGTEFWQ0lHVFMqKnwgKDIwMTUgb25seSkgYmFzZWQgb24gYW5zd2VyIHRvICJXaGljaCBvZiB0aGUgZm9sbG93aW5nIHRvYmFjY28gcHJvZHVjdHMgdGhhdCB5b3UgdXNlZCBpbiB0aGUgcGFzdCAzMCBkYXlzIHdlcmUgZmxhdm9yZWQ/IiAKKipDQklESVMqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgdGhleSBzbW9rZWQgYmlkaXMgZHVyaW5nIHRoZSBwYXN0IDMwIGRheXMgIAoqKkNIT09LQUgqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgdGhleSBzbW9rZWQgdG9iYWNjbyBpbiBhIGhvb2thaCBvbiA+PSAxIG9mIHRoZSBwYXN0IDMwIGRheXMgIAoqKkNQSVBFKiogfCBzdHVkZW50IHJlcG9ydGVkIHRoZXkgc21va2VkIHRvYmFjY28gaW4gYSBwaXBlIChub3QgaG9va2FoKSBkdXJpbmcgdGhlIHBhc3QgMzAgZGF5cyAgCioqQ1NOVVMqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgdGhleSB1c2VkIHNudXMgZHVyaW5nIHRoZSBwYXN0IDMwIGRheXMgICAgCioqQ0RJU1NPTFYqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgdGhleSB1c2VkIGRpc3NvbHZhYmxlIHRvYmFjY28gcHJvZHVjdHMgc3VjaCBhcyBBcml2YSwgU3RvbmV3YWxsLCBDYW1lbCBvcmJzLCBDYW1lbCBzdGlja3MsIE1hcmxib3JvIHN0aWNrcywgb3IgQ2FtZWwgc3RyaXBzIGR1cmluZyB0aGUgcGFzdCAzMCBkYXlzICAKKipicmFuZF9lY2lnKiogfCBzdHVkZW50IGFuc3dlciB0byAiRHVyaW5nIHRoZSBwYXN0IDMwIGRheXMsIHdoYXQgYnJhbmQgb2YgZS1jaWdhcmV0dGVzIGRpZCB5b3UgdXN1YWxseSB1c2U/IiAgCioqbWVudGhvbCoqIHwgc3R1ZGVudCBzZWxlY3RlZCBNZW50aG9sIG9yIG1pbnQgYXMgdGhlIGFuc3dlciB0byAiV2hhdCBmbGF2b3JzIG9mIHRvYmFjY28gcHJvZHVjdHMgaGF2ZSB5b3UgdXNlZCBpbiB0aGUgcGFzdCAzMCBkYXlzPyAoc2VsZWN0IG9uZSBvciBtb3JlKSIgIAoqKmNsb3ZlX3NwaWNlKiogfCBzdHVkZW50IHNlbGVjdGVkIGNsb3ZlIG9yIHNwaWNlIGFzIHRoZSBhbnN3ZXIgdG8gIldoYXQgZmxhdm9ycyBvZiB0b2JhY2NvIHByb2R1Y3RzIGhhdmUgeW91IHVzZWQgaW4gdGhlIHBhc3QgMzAgZGF5cz8gKHNlbGVjdCBvbmUgb3IgbW9yZSkiICAKKipmcnVpdCoqIHwgc3R1ZGVudCBzZWxlY3RlZCBmcnVpdCBhcyB0aGUgYW5zd2VyIHRvICJXaGF0IGZsYXZvcnMgb2YgdG9iYWNjbyBwcm9kdWN0cyBoYXZlIHlvdSB1c2VkIGluIHRoZSBwYXN0IDMwIGRheXM/IChzZWxlY3Qgb25lIG9yIG1vcmUpIiAgCioqY2hvY29sYXRlKiogfCBzdHVkZW50IHNlbGVjdGVkIGNob2NvbGF0ZSBhcyB0aGUgYW5zd2VyIHRvICJXaGF0IGZsYXZvcnMgb2YgdG9iYWNjbyBwcm9kdWN0cyBoYXZlIHlvdSB1c2VkIGluIHRoZSBwYXN0IDMwIGRheXM/IChzZWxlY3Qgb25lIG9yIG1vcmUpIiAgCioqYWxjb2hvbGljX2RyaW5rKiogfCBzdHVkZW50IHNlbGVjdGVkIGFsY29ob2xpYyBkcmluayAoc3VjaCBhcyB3aW5lLCBjb2duYWMsIG1hcmdhcml0YSwgb3Igb3RoZXIgY29ja3RhaWxzKSBhcyB0aGUgYW5zd2VyIHRvICJXaGF0IGZsYXZvcnMgb2YgdG9iYWNjbyBwcm9kdWN0cyBoYXZlIHlvdSB1c2VkIGluIHRoZSBwYXN0IDMwIGRheXM/IChjaG9vc2Ugb25lIG9yIG1vcmUpIiAgCioqY2FuZHlfZGVzc2VydF9zd2VldHMqKiB8ICBzdHVkZW50IHNlbGVjdGVkIGNhbmR5LCBkZXNzZXJ0cyBvciBvdGhlciBzd2VldHMgYXMgdGhlIGFuc3dlciB0byAiV2hhdCBmbGF2b3JzIG9mIHRvYmFjY28gcHJvZHVjdHMgaGF2ZSB5b3UgdXNlZCBpbiB0aGUgcGFzdCAzMCBkYXlzPyAoY2hvb3NlIG9uZSBvciBtb3JlKSIgCioqb3RoZXIqKiB8IHN0dWRlbnQgc2VsZWN0ZWQgc29tZSBvdGhlciBmbGF2b3Igbm90IGxpc3RlZCBhcyB0aGUgYW5zd2VyIHRvICJXaGF0IGZsYXZvcnMgb2YgdG9iYWNjbyBwcm9kdWN0cyBoYXZlIHlvdSB1c2VkIGluIHRoZSBwYXN0IDMwIGRheXM/IChjaG9vc2Ugb25lIG9yIG1vcmUpIiAKKipub191c2UqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgdGhhdCB0aGV5IGRpZCBub3QgdXNlIGFueSBmbGF2b3JlZCB0b2JhY2NvIHByb2R1Y3RzIGluIHRoZSBwYXN0IDMwIGRheXMgb3IgZGlkIG5vdCBhbnN3ZXIgdGhlIHF1ZXN0aW9uIGFib3V0IHVzaW5nIGZsYXZvcnMKKipFSFRQKiogfCBzdHVkZW50IHJlcG9ydGVkIGhhdmluZyBldmVyIHRyaWVkIGhlYXRlZCAoYWxzbyBrbm93biBhcyAiaGVhdC1ub3QtYnVybiIpIHRvYmFjY28gcHJvZHVjdHMgIAoqKkNIVFAqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgdGhleSB1c2VkIGhlYXRlZCB0b2JhY2NvIHByb2R1Y3RzIGR1cmluZyB0aGUgcGFzdCAzMCBkYXlzICAKPC9kZXRhaWxzPgoKIyMgKipEYXRhIFZpc3VhbGl6YXRpb24qKgoqKiogCgpSZWNhbGwgdGhhdCBvdXIgbWFpbiBxdWVzdGlvbnMgd2VyZToKCjEpIEhvdyBoYXMgdG9iYWNjbyBhbmQgZS1jaWdhcmV0dGUgdXNlIGJ5IEFtZXJpY2FuIHlvdXRocyBjaGFuZ2VkIHNpbmNlIDIwMTU/CjIpIEhvdyBkbyB2YXBpbmcgcmF0ZXMgY29tcGFyZSBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzPwozKSBXaGF0IHZhcGluZyBicmFuZHMgYW5kIGZsYXZvcnMgYXBwZWFyIHRvIGJlIHVzZWQgdGhlIG1vc3QgZnJlcXVlbnRseT8gIApXZSB3aWxsIGJhc2UgdGhpcyBvbiB0aGUgZm9sbG93aW5nIHN1cnZleSBxdWVzdGlvbnM6ICAgCj4gIkR1cmluZyB0aGUgcGFzdCAzMCBkYXlzLCB3aGF0IGJyYW5kIG9mIGUtY2lnYXJldHRlcyBkaWQgeW91IHVzdWFsbHkgdXNlPyIgICAKPiIgV2hhdCBmbGF2b3JzIG9mIHRvYmFjY28gcHJvZHVjdHMgaGF2ZSB5b3UgdXNlZCBpbiB0aGUgcGFzdAozMCBkYXlzPyIgCgo0KSBJcyB0aGVyZSBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGUtY2lnYXJldHRlL3ZhcGluZyB1c2UgYW5kIG90aGVyIHRvYmFjY28gdXNlPwoKCldlIGFyZSBub3cgZ29pbmcgdG8gY3JlYXRlIGRhdGEgdmlzdWFsaXphdGlvbnMgdG8gZXhwbG9yZSBlYWNoIG9mIHRoZXNlIHF1ZXN0aW9ucy4KCkZvciBtYW55IG9mIHRoZXNlIHF1ZXN0aW9ucyB3ZSB3aWxsIGJlIGludGVyZXN0ZWQgaW4gYm90aCAqKmN1cnJlbnQqKiBhbmQgKipldmVyKiogdXNlcnMsIHNvIHdlIHdpbGwgd2FudCB0byBjcmVhdGUgYSB2YXJpYWJsZSBmb3IgbGFiZWxpbmcgaW5kaXZpZHVhbHMgd2hvIGFyZSBjdXJyZW50IHVzZXJzIG9mIGFueSB0b2JhY2NvIHByb2R1Y3QgKG9yIG5vdCwgaS5lLiwgd2hvIGRvIG5vdCBjdXJyZW50bHkgdXNlIGEgdG9iYWNjbyBwcm9kdWN0KSBhbmQgYSB2YXJpYWJsZSBmb3IgbGFiZWxpbmcgaW5kaXZpZHVhbHMgd2hvIGFyZSAiZXZlciB1c2VycyIgb2YgYW55IHRvYmFjY28gcHJvZHVjdCAob3Igbm90LCBpLmUuLCB3aG8gaGF2ZSBuZXZlciB1c2VkIGEgdG9iYWNjbyBwcm9kdWN0KS4KCldlIGRlZmluZSB0aGVzZSB0d28gZ3JvdXBzIGFzIGZvbGxvd3M6CgoxKSAqKmN1cnJlbnQqKiA9IHN0dWRlbnRzIHdobyB1c2VkIGEgcHJvZHVjdCBmb3IgPj0xIGRheSBpbiB0aGUgcGFzdCAzMCBkYXlzICAKMikgKipldmVyKiogPSAgc3R1ZGVudHMgd2hvIHJlcG9ydCBoYXZpbmcgdXNlZCBvciB0cmllZCBhIHByb2R1Y3QgYXQgYW55IHBvaW50IGluIHRpbWUKCkFsbCAqKmN1cnJlbnQqKiB1c2VycyBhcmUgdGhlcmVmb3JlICoqZXZlcioqIHVzZXJzIGJ1dCBub3QgYWxsICoqZXZlcioqIHVzZXJzIGFyZSAqKmN1cnJlbnQqKiB1c2Vycy4gVGh1cywgKipjdXJyZW50KiogdXNlcnMgYXJlIGEgc3Vic2V0IG9mICoqZXZlcioqIHVzZXJzLgoKVG8gYWRkIHRoZXNlIGdyb3VwaW5nIHZhcmlhYmxlcyB0byBvdXIgZGF0YSB3ZSB3aWxsIGRvIGEgYml0IG1vcmUgd3JhbmdsaW5nIHVzaW5nIHRoZSBgbXV0YXRlKClgIGZ1bmN0aW9uIGFnYWluIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIEFzIGRpc2N1c3NlZCBhYm92ZSwgb3VyIGRhdGEgc2V0IGNvbnRhaW5zIGEgc2V0IG9mIHF1ZXN0aW9ucyB0aGF0IHJlbGF0ZSB0byB3aGV0aGVyIHRoZSBzdHVkZW50IGhhcyBldmVyIHVzZWQgdGhlIHBhcnRpY3VsYXIgdG9iYWNjbyBwcm9kdWN0IChxdWVzdGlvbnMgdGhhdCBzdGFydCB3aXRoIHRoZSBsZXR0ZXIgIkUiKSwgYW5kIHF1ZXN0aW9ucyB0aGF0IHJlbGF0ZSB0byB3aGV0aGVyIHRoZSBzdHVkZW50IGN1cnJlbnRseSB1c2VzIHRoZSBwYXJ0aWN1bGFyIHRvYmFjY28gcHJvZHVjdCAocXVlc3Rpb25zIHRoYXQgc3RhcnQgd2l0aCB0aGUgbGV0dGVyICJDIikuIAoKSGVyZSBhcmUgc29tZSBleGFtcGxlcyBmb3IgdGhlc2UgZGF0YSBlbnRyaWVzOiAgCgogLSBFUElQRTogU3R1ZGVudHMgd2hvIHJlcG9ydGVkIHRoZXkgaGF2ZSBzbW9rZWQgdG9iYWNjbyBmcm9tIGEgcGlwZSAobm90IGhvb2thaCkuICAKIC0gQ1BJUEU6IFN0dWRlbnRzIHdobyByZXBvcnRlZCB0aGV5IHNtb2tlZCB0b2JhY2NvIGluIGEgcGlwZSAobm90IGhvb2thaCkgZHVyaW5nIHRoZSBwYXN0IDMwIGRheXMuIAogLSBFUk9MTENJR1RTOiBSRUNPREU6IFN0dWRlbnRzIHdobyByZXBvcnRlZCB0aGV5IGhhdmUgdHJpZWQgc21va2luZyByb2xsLXlvdXItb3duIGNpZ2FyZXR0ZXMuIAogLSBDUk9MTENJR1RTOiBSRUNPREU6IFN0dWRlbnRzIHdobyByZXBvcnRlZCB0aGV5IHNtb2tlZCByb2xsLXlvdXItb3duIGNpZ2FyZXR0ZXMgZHVyaW5nIHRoZSBwYXN0IDMwIGRheXMuIAogCkJhc2VkIG9uIG1hbnkgcXVlc3Rpb25zIGxpa2UgdGhpczogIAogCiBJbiB0aGUgcGFzdCAzMCBkYXlzLCB3aGljaCBvZiB0aGUgZm9sbG93aW5nIHByb2R1Y3RzIGhhdmUgeW91IHVzZWQgb24gYXQgbGVhc3Qgb25lIGRheT8gKFNlbGVjdCBvbmUgb3IgbW9yZSkgCkEuIFJvbGwteW91ci1vd24gY2lnYXJldHRlcyAgCkIuIFBpcGVzIGZpbGxlZCB3aXRoIHRvYmFjY28gKG5vdCBob29rYWggb3Igd2F0ZXJwaXBlKSAgCkMuIFNudXMsIHN1Y2ggYXMgQ2FtZWwsIE1hcmxib3JvLCBvciBHZW5lcmFsIFNudXMgIApELiBEaXNzb2x2YWJsZSB0b2JhY2NvIHByb2R1Y3RzIHN1Y2ggYXMgQXJpdmEsIFN0b25ld2FsbCwgQ2FtZWwgb3JicywgQ2FtZWwgc3RpY2tzLCBNYXJsYm9ybyBzdGlja3MsCm9yIENhbWVsIHN0cmlwcyAgCkUuIEJpZGlzIChzbWFsbCBicm93biBjaWdhcmV0dGVzIHdyYXBwZWQgaW4gYSBsZWFmKSAgCkYuIEkgaGF2ZSBub3QgdXNlZCBhbnkgb2YgdGhlIHByb2R1Y3RzIGxpc3RlZCBhYm92ZSBpbiB0aGUgcGFzdCAzMCBkYXlzICAKCiBXaGljaCBvZiB0aGUgZm9sbG93aW5nIHRvYmFjY28gcHJvZHVjdHMgaGF2ZSB5b3UgZXZlciB0cmllZCwgZXZlbiBqdXN0IG9uZSB0aW1lPyAoU2VsZWN0IG9uZSBvciBtb3JlKSAgCkEuIFJvbGwteW91ci1vd24gY2lnYXJldHRlcyAgCkIuIFBpcGVzIGZpbGxlZCB3aXRoIHRvYmFjY28gKG5vdCBob29rYWggb3Igd2F0ZXJwaXBlKSAgCkMuIFNudXMsIHN1Y2ggYXMgQ2FtZWwsIE1hcmxib3JvLCBvciBHZW5lcmFsIFNudXMgIApELiBEaXNzb2x2YWJsZSB0b2JhY2NvIHByb2R1Y3RzIHN1Y2ggYXMgQXJpdmEsIFN0b25ld2FsbCwgQ2FtZWwgb3JicywgQ2FtZWwgc3RpY2tzLCBNYXJsYm9ybyBzdGlja3MsIG9yIENhbWVsIHN0cmlwcyAgCkUuIEJpZGlzIChzbWFsbCBicm93biBjaWdhcmV0dGVzIHdyYXBwZWQgaW4gYSBsZWFmKSAgCkYuIEkgaGF2ZSBuZXZlciB0cmllZCBhbnkgb2YgdGhlIHByb2R1Y3RzIGxpc3RlZCBhYm92ZSAgIAogCiAKV2Ugd2lsbCBzdW0gYWNyb3NzIHRoZSB2YXJpYWJsZXMgdGhhdCByZWxhdGUgdG8gZXZlciBvciBjdXJyZW50IHRvYmFjY28gdXNhZ2UgcXVlc3Rpb25zIHRvIGRldGVybWluZSBpZiB0aGUgc3R1ZGVudCBhbnN3ZXJlZCB5ZXMgdG8gYW55IG9mIHRoZSBldmVyIG9yIGN1cnJlbnQgcXVlc3Rpb25zLiAKCldlIHdpbGwgdGhlbiB1c2UgdGhlIGBjYXNlX3doZW4oKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byBjb252ZXJ0IHRoZSBzdW0gdmFsdWVzIHRvIGBUUlVFYCBvciBgRkFMU0VgIGJhc2VkIG9uIHRoZSB0aHJlc2hvbGQgb2YgemVyby4gSWYgdGhlIHN1bSBpcyBncmVhdGVyIHRoYW4gemVybywgdGhlbiB3ZSBrbm93IHRoZSBzdHVkZW50IGFuc3dlcmVkIHllcyB0byBhdCBsZWFzdCBvbmUgcXVlc3Rpb24uIAogCmBgYHtyfQpueXRzX2RhdGEgPC1ueXRzX2RhdGEgJT4lCiAgICBtdXRhdGUodG9iYWNjb19zdW1fZXZlciA9IHNlbGVjdCguLCBzdGFydHNfd2l0aCgiRSIsIGlnbm9yZS5jYXNlID0gRkFMU0UpKSAlPiUKICAgICAgICAgICAgICAgYmFzZTo6YXBwbHkoMSwgc3VtLCBuYS5ybT1UUlVFKSwKICAgICAgICAgICB0b2JhY2NvX3N1bV9jdXJyZW50ID0gc2VsZWN0KC4sIHN0YXJ0c193aXRoKCJDIiwgaWdub3JlLmNhc2UgPSBGQUxTRSkpICU+JQogICAgICAgICAgICAgICBhcHBseSgxLCBzdW0sIG5hLnJtPVRSVUUpKSAlPiUKICAgIG11dGF0ZSh0b2JhY2NvX2V2ZXIgPSBjYXNlX3doZW4odG9iYWNjb19zdW1fZXZlciA+IDAgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b2JhY2NvX3N1bV9ldmVyID09IDAgfiBGQUxTRSksCiAgICAgICAgICAgdG9iYWNjb19jdXJyZW50ID0gY2FzZV93aGVuKHRvYmFjY29fc3VtX2N1cnJlbnQgPiAwIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9iYWNjb19zdW1fY3VycmVudCA9PSAwIH4gRkFMU0UpKSAKCmBgYAoKCiMjIyMgey5zY3JvbGxhYmxlfQpgYGB7cn0KZ2xpbXBzZShueXRzX2RhdGEpCmBgYAojIyMjCgpXZSBhcmUgYWxzbyBpbnRlcmVzdGVkIGluIGUtY2lnYXJldHRlIHVzYWdlIGNvbXBhcmVkIHRvIG90aGVyIHRvYmFjY28gcHJvZHVjdHMsIHNvIHdlIHdpbGwgY3JlYXRlIHNvbWUgdmFyaWFibGVzIHJlbGF0ZWQgdG8gdGhlIHN1bSBvZiBhbGwgZS1jaWdhcmV0dGUgdXNhZ2UgcXVlc3Rpb24gdmFyaWFibGVzIGFuZCB0aGUgc3VtIG9mIGFsbCB0b2JhY2NvIHVzYWdlIHF1ZXN0aW9uIHZhcmlhYmxlcyBleGNsdWRpbmcgdGhvc2UgdGhhdCBhcmUgYWJvdXQgZS1jaWdhcmV0dGVzLiBUaGVyZSBpcyBvbmx5IG9uZSB2YXJpYWJsZSBhYm91dCBlLWNpZ2FyZXR0ZSB1c2FnZSBldmVyIChFRUxDSUdUKSBhbmQgb25lIGFib3V0IGN1cnJlbnQgdXNhZ2UgKENFTENJR1QpLgoKYGBge3J9CiAgIG55dHNfZGF0YSA8LW55dHNfZGF0YSAlPiUgbXV0YXRlKGVjaWdfc3VtX2V2ZXIgPSBzZWxlY3QoLiwgRUVMQ0lHVCkgJT4lCiAgICAgICAgICAgICAgIGFwcGx5KDEsIHN1bSwgbmEucm09VFJVRSksCiAgICAgICAgICAgZWNpZ19zdW1fY3VycmVudCA9IHNlbGVjdCguLCBDRUxDSUdUKSAlPiUKICAgICAgICAgICAgICAgYXBwbHkoMSwgc3VtLCBuYS5ybT1UUlVFKSwKICAgICAgICAgICBub25fZWNpZ19zdW1fZXZlciA9IHNlbGVjdCguLCBzdGFydHNfd2l0aCgiRSIsIGlnbm9yZS5jYXNlID0gRkFMU0UpKSAlPiUKICAgICAgICAgICAgICAgc2VsZWN0KC4sLUVFTENJR1QpICU+JQogICAgICAgICAgICAgICBhcHBseSgxLCBzdW0sIG5hLnJtPVRSVUUpLAogICAgICAgICAgIG5vbl9lY2lnX3N1bV9jdXJyZW50ID0gc2VsZWN0KC4sIHN0YXJ0c193aXRoKCJDIiwgaWdub3JlLmNhc2UgPSBGQUxTRSkpICU+JQogICAgICAgICAgICAgICBzZWxlY3QoLiwtQ0VMQ0lHVCkgJT4lCiAgICAgICAgICAgICAgIGFwcGx5KDEsIHN1bSwgbmEucm09VFJVRSkpICU+JQogICAgbXV0YXRlKGVjaWdfZXZlciA9IGNhc2Vfd2hlbihlY2lnX3N1bV9ldmVyID4gMCB+IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfc3VtX2V2ZXIgPT0gMCB+IEZBTFNFKSwKICAgICAgICAgICBlY2lnX2N1cnJlbnQgPSBjYXNlX3doZW4oZWNpZ19zdW1fY3VycmVudCA+IDAgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX3N1bV9jdXJyZW50ID09IDAgfiBGQUxTRSksCiAgICAgICAgICAgbm9uX2VjaWdfZXZlciA9IGNhc2Vfd2hlbihub25fZWNpZ19zdW1fZXZlciA+IDAgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19zdW1fZXZlciA9PSAwIH4gRkFMU0UpLAogICAgICAgICAgIG5vbl9lY2lnX2N1cnJlbnQgPSBjYXNlX3doZW4obm9uX2VjaWdfc3VtX2N1cnJlbnQgPiAwIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfc3VtX2N1cnJlbnQgPT0gMCB+IEZBTFNFKSkKYGBgCgoKCiMjIyMgey5zY3JvbGxhYmxlfQpgYGB7cn0KZ2xpbXBzZShueXRzX2RhdGEpCmBgYAoKIyMjIwoKRmluYWxseSwgd2UgYXJlIGFsc28gaW50ZXJlc3RlZCBpbiBncm91cGluZyBzdHVkZW50cyB0aGF0IG9ubHkgdXNlIGUtY2lnYXJldHRlcyBhbmQgdGhvc2UgdGhhdCBvbmx5IHVzZSBvdGhlciBmb3JtcyBvZiB0b2JhY2NvLgoKUmVjYWxsIHRoYXQgY3VycmVudCB1c2VycyBhcmUgYSBzdWJzZXQgb2YgZXZlciB1c2VycywgdGh1cyBzdHVkZW50cyB3b3VsZCB0eXBpY2FsbHkgYW5zd2VyIHllcyB0byBoYXZpbmcgdHJpZWQgdmFwaW5nIHByb2R1Y3RzIGlmIHRoZXkgaGFkIHVzZWQgdGhlbSBvbmUgb3IgbW9yZSBkYXlzIGluIHRoZSBwYXN0IDMwIGRheXMuCgpGaXJzdCB3ZSB3aWxsIG1ha2UgYSBzbWFsbCB0b3kgZGF0YXNldCBjYWxsZWQgYHRlc3RgIHRvIHNob3cgd2hhdCB3ZSB3aWxsIGRvIHdpdGggdGhlIGxhcmdlciBkYXRhc2V0OgpgYGB7cn0KdGVzdCA8LSB0aWJibGUoZWNpZ19ldmVyID0gYygiVFJVRSIsICJUUlVFIiwgIlRSVUUiLCAiVFJVRSIsICJGQUxTRSIsICJGQUxTRSIsICJUUlVFIiwgIkZBTFNFIiwgIkZBTFNFIiksCiAgICAgICAgICAgICAgIG5vbl9lY2lnX2V2ZXIgPSBjKCJUUlVFIiwgIkZBTFNFIiwiRkFMU0UiLCJGQUxTRSIsICJGQUxTRSIsICJGQUxTRSIsICJUUlVFIiwgIlRSVUUiLCAiVFJVRSIpLAogICAgICAgICAgICAgICBlY2lnX2N1cnJlbnQgPSBjKCJUUlVFIiwgIkZBTFNFIiwiRkFMU0UiLCAiVFJVRSIsICJUUlVFIiwgIkZBTFNFIiwgIkZBTFNFIiwgIkZBTFNFIiwgIkZBTFNFIiksCiAgICAgICAgICAgICAgIG5vbl9lY2lnX2N1cnJlbnQgPSBjKCJUUlVFIiwgIkZBTFNFIiwiVFJVRSIsICJGQUxTRSIsICJUUlVFIiwgIkZBTFNFIiwgIkZBTFNFIiwgIkZBTFNFIiwgIlRSVUUiKSkKCnRlc3QKYGBgCgpOb3csIGxldCdzIGxvb2sgYXQgaWRlbnRpZnlpbmcgc3R1ZGVudHMgd2hvIGhhdmUgdHJpZWQgZS1jaWdhcmV0dGVzLCBidXQgYXJlIG5vdCBjdXJyZW50IHVzZXJzLCBhbmQgd2hvIGhhdmUgbmV2ZXIgdHJpZWQgb3RoZXIgdG9iYWNjbyBwcm9kdWN0cyAoYW5kIGFyZSB0aGVyZWZvcmUgbm90IGN1cnJlbnQgdXNlcnMpLiBXZSB3aWxsIGFnYWluIHVzZSB0aGUgYGNhc2Vfd2hlbigpYCBhbmQgdGhlIGBtdXRhdGVgIGZ1bmN0aW9uIHRvIGNyZWF0ZSBuZXcgdmFyaWFibGVzIHdpdGggc3BlY2lmaWMgdmFsdWVzIHdoZW4gY2VydGFpbiBjb25kaXRpb25zIGFyZSBtZXQuIEluIHRoaXMgY2FzZSwgd2Ugd2lsbCBzcGVjaWZ5IHRoYXQgc2V2ZXJhbCBjb25kaXRpb25zIG11c3QgYmUgbWV0IGJ5IHVzaW5nIHRoZSBgJmAgc3ltYm9sLiBGb3IgYSB2YWx1ZSBvZiBgVFJVRWAgZm9yIHRoZSBuZXcgYGVjaWdfb25seV9ldmVyYCB2YXJpYWJsZSwgYWxsIG9mIHRoZSBjb25kaXRpb25zIGNvbWJpbmVkIHdpdGggYCZgIG11c3QgYmUgbWV0LiAgSWYgYW55IG9mIHRoZSBjb25kaXRpb25zIGFyZSBub3QgbWV0IHRoZW4gdGhlIGBlY2lnX29ubHlfZXZlcmAgdmFsdWUgd2lsbCBiZSBgRkFMU0VgIGJhc2VkIG9uIHRoZSBsYXN0IGxpbmUgYFRSVUUgfiBGQUxTRWAuCgpgYGB7cn0KCnRlc3QgPC0gdGVzdCAlPiUgbXV0YXRlKGVjaWdfb25seV9ldmVyID0gY2FzZV93aGVuKGVjaWdfZXZlciA9PSBUUlVFICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfZXZlciA9PSBGQUxTRSAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX2N1cnJlbnQgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX2N1cnJlbnQgPT0gRkFMU0UgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpKQp0ZXN0CmBgYAoKV2UgY2FuIHNlZSBmcm9tIHRoZSBzZWNvbmQgcm93LCB0aGF0IHRoZSBgZWNpZ19vbmx5X2V2ZXJgIGlzIGBUUlVFYCB3aGVuIHdlIHdvdWxkIGV4cGVjdCBpdCB0byBiZS4KV2UgY2FuIGFsc28gc2VlIGZyb20gdGhlIGZvdXJ0aCByb3csIHRoYXQgZXZlbiB0aG91Z2ggdGhlIHN0dWRlbnQgcmVwb3J0ZWQgeWVzIHRvIGV2ZXIgdHJ5aW5nIGUtY2lnYXJldHRlcywgYmVjYXVzZSB0aGV5IGFsc28gcmVwb3J0ZWQgeWVzIHRvIGN1cnJlbnRseSB1c2luZyBlLWNpZ2FyZXR0ZXMgdGhlIHZhbHVlIGZvciBvbmx5IGV2ZXIgdHJ5aW5nIGUtY2lnYXJldHRlcyBpcyBgRkFMU0VgLiBBZGRpdGlvbmFsbHkgd2UgY2FuIHNlZSBmcm9tIHRoZSBzZXZlbnRoIHJvdyB0aGF0IHNpbWlsYXJseSBldmVuIHRob3VnaCB0aGUgc3R1ZGVudCByZXBvcnRlZCB5ZXN0IHRvIGV2ZXIgdHJ5aW5nIGUtY2lnYXJldHRlcywgdGhleSBhbHNvIHJlcG9ydGVkIHllcyB0byBldmVyIHRyeWluZyBvdGhlciBwcm9kdWN0cywgYW5kIHRoZSB2YWx1ZSBmb3Igb25seSBldmVyIHRyeWluZyBlLWNpZ2FyZXR0ZXMgaXMgYEZBTFNFYC4gSW1wb3J0YW50bHksIHdlIGNhbiBzZWUgZnJvbSB0aGUgNnRoIHJvdywgdGhhdCBpZiBhbGwgcmVzcG9uc2VzIGFyZSBuZWdhdGl2ZSB0aGFuIHRoZSB2YWx1ZSBpcyBgRkFMU0VgLgoKTm93IHdlIHdpbGwgZXhwYW5kIHRoaXMgdG8gdGhlIG90aGVyIHBvc3NpYmxlIGNhdGVnb3JpZXMuIEluIHRoaXMgY2FzZSB3ZSBub3RlIHRoYXQgc2luY2UgY3VycmVudCB1c2VycyBhcmUgYSBzdWJzZXQgb2YgZXZlciB1c2VycywgaXQgZG9lc24ndCBtYXR0ZXIgaWYgYSB1c2VyIHJlcG9ydHMgeWVzIHRvIGV2ZXIgdHJ5aW5nICBlLWNpZ2FyZXR0ZXMsIHRoZXkgY2FuIHN0aWxsIGJlIGEgY3VycmVudCB1c2VyLgoKCmBgYHtyfQp0ZXN0IDwtdGVzdCAlPiUgbXV0YXRlKGVjaWdfb25seV9ldmVyID0gY2FzZV93aGVuKGVjaWdfZXZlciA9PSBUUlVFICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19ldmVyID09IEZBTFNFICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19jdXJyZW50ID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX2N1cnJlbnQgPT0gRkFMU0UgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IEZBTFNFKSwKICAgICAgICAgICAgICAgICBlY2lnX29ubHlfY3VycmVudCA9IGNhc2Vfd2hlbihlY2lnX2N1cnJlbnQgPT0gVFJVRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19ldmVyID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX2N1cnJlbnQgPT0gRkFMU0UgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IEZBTFNFKSwKICAgICAgICAgICAgICAgbm9uX2VjaWdfb25seV9ldmVyID0gY2FzZV93aGVuKG5vbl9lY2lnX2V2ZXIgPT0gVFJVRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19ldmVyID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX2N1cnJlbnQgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfY3VycmVudCA9PSBGQUxTRSB+IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBGQUxTRSksCiAgICAgICAgIG5vbl9lY2lnX29ubHlfY3VycmVudCA9IGNhc2Vfd2hlbihub25fZWNpZ19jdXJyZW50ID09IFRSVUUgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfZXZlciA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19jdXJyZW50ID09IEZBTFNFIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBub191c2UgPSBjYXNlX3doZW4obm9uX2VjaWdfZXZlciA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19ldmVyID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX2N1cnJlbnQgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfY3VycmVudCA9PSBGQUxTRSB+VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpKSAKZ2xpbXBzZSh0ZXN0KQpgYGAKCgoKVGFrZSBhIG1pbnV0ZSB0byBjaGVjayB0aGF0IHRoZSB2YWx1ZXMgYXJlIHdoYXQgd2Ugd291bGQgZXhwZWN0LgoKT0ssIG5vdyB3ZSBhcmUgZ29pbmcgdG8gbWFrZSBhIGBHcm91cGAgdmFyaWFibGUgYmFzZWQgb24gdGhlIG5ldyB2YXJpYWJsZXMgd2UganVzdCBtYWRlIHRvIGNsYXNzaWZ5IHN0dWRlbnRzIGludG8gb25lIG9mIGZvdXIgbXV0dWFsbHkgZXhjbHVzaXZlIGFuZCBleGhhdXN0aXZlIGNhdGVnb3JpZXMuIEluIHRoaXMgY2FzZSB3ZSB3aWxsIGhhdmUgYSBwYXJ0aWN1bGFyIHZhbHVlIGJhc2VkIG9uIG9uZSBjb25kaXRpb24gKipvcioqIGFub3RoZXIuIFRoaXMgKipvcioqIGNvbmRpdGlvbmFsIGlzIHNwZWNpZmllZCBieSB0aGUgYHxgIHN5bWJvbC4gT25seSBvbmUgb2YgdGhlIGNvbmRpdGlvbnMgbmVlZHMgdG8gZXhpc3QgZm9yIHRoYXQgcGFydGljdWxhciB2YWx1ZSwgd2hlcmVhcyB3aGVuIHdlIHVzZWQgdGhlIGAmYCBzeW1ib2wsIGFsbCBvZiB0aGUgY29uZGl0aW9ucyBoYWQgdG8gYmUgbWV0LiBJZiBhIHN0dWRlbnQgaGFzIGV2ZXIgdHJpZWQgb3IgY3VycmVudGx5IHVzZXMgZS1jaWdhcmV0dGVzLCBidXQgaGFzIG5ldmVyIHRyaWVkIG90aGVyIHRvYmFjY28gcHJvZHVjdHMsIHRoZSB2YWx1ZSB3aWxsIGJlIGBPbmx5IGUtY2lnYXJldHRlc2AuIElmIGEgc3R1ZGVudCBoYXMgZXZlciB0cmllZCBvciBpcyBhIGN1cnJlbnQgdXNlciBvZiBvdGhlciB0b2JhY2NvIHByb2R1Y3RzLCBidXQgaGFzIG5ldmVyIHRyaWVkIGUtY2lnYXJldHRlcywgdGhlIHZhbHVlIHdpbGwgYmUgYE9ubHkgb3RoZXIgcHJvZHVjdHNgLiBJZiB0aGUgdmFsdWUgb2YgdGhlIGBub191c2VgIHZhcmlhYmxlIGlzIHNpbXBseSBgVFJVRWAsIHRoZW4gdGhlIGBHcm91cGAgdmFyaWFibGUgdmFsdWUgd2lsbCBiZSBgTmVpdGhlcmAuIEZpbmFsbHksIGlmIGEgc3R1ZGVudCBoYXMgdHJpZWQgb3IgY3VycmVudGx5IHVzZXMgYm90aCBlLWNpZ2FyZXR0ZXMgYW5kIG90aGVyIHRvYmFjY28gcHJvZHVjdHMgdGhlIGBHcm91cGAgdmFyaWFibGUgdmFsdWUgd2lsbCBiZSBgQ29tYmluYXRpb24gb2YgcHJvZHVjdHNgLiBUaGVyZWZvcmUgdGhlIHZhbHVlcyBmb3IgdGhlIHVzYWdlIG9mIHRoZSB2YXJpYWJsZXMgYmFzZWQgb24gb25seSB1c2luZyBlLWNpZ2FyZXR0ZXMgb3Igb25seSBvdGhlciBwcm9kdWN0cyB3aWxsIGFsbCBiZSBgRkFMU0VgLiBPZiBjb3Vyc2UgdGhlIHN0dWRlbnQgd2lsbCBhbHNvIGhhdmUgaGFkIHRvIGFuc3dlciB5ZXMgdG8gYW55IG9mIHRoZSB1c2UtYmFzZWQgcXVlc3Rpb25zLCB0aHVzIHRoZSBub191c2UgdmFyaWFibGUgd291bGQgYWxzbyBuZWVkIHRvIGJlIGBGQUxTRWAuCgpBVk9DQURPOiBDb25zaWRlciBkcm9wcGluZyB0aGUgbGFzdCB0d28gc2VudGVuY2VzIGluIHRoZSBwYXJhZ3JhcGggYWJvdmU/IGkuZS4sIGZyb20gIlRoZXJlZm9yZSB0aGUgdmFsdWVzLi4uIiB0byAid291bGQgYWxzbyBuZWVkIHRvIGJlIGBGQUxTRWAuIiBJJ20gbm90IHN1cmUgd2hhdCB0aGV5IGFyZSBhZGRpbmcuIExFQVZFIElOIEZPUiBDQVJSSUUgVE8gUkVWSUVXLgoKYGBge1J9Cgp0ZXN0IDwtIHRlc3QgJT4lIAogIG11dGF0ZShHcm91cCA9IGNhc2Vfd2hlbihlY2lnX29ubHlfZXZlciA9PSBUUlVFIHwKICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19vbmx5X2N1cnJlbnQgPT0gVFJVRSB+ICJPbmx5IGUtY2lnYXJldHRlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfb25seV9ldmVyID09IFRSVUUgfAogICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX29ubHlfY3VycmVudCA9PSBUUlVFIH4gIk9ubHkgb3RoZXIgcHJvZHVjdHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vX3VzZSA9PSBUUlVFIH4gIk5laXRoZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX29ubHlfZXZlciA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfb25seV9jdXJyZW50ID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19vbmx5X2V2ZXIgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX29ubHlfY3VycmVudCA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9fdXNlID09IEZBTFNFIH4gIkNvbWJpbmF0aW9uIG9mIHByb2R1Y3RzIikpCgoKdGVzdCAlPiUgY291bnQoR3JvdXApCgpnbGltcHNlKHRlc3QpCmBgYAoKT0ssIG5vdyB0aGF0IHdlIGhhdmUgc2VlbiBob3cgdGhpcyB3b3JrcyB3aXRoIG91ciB0b3kgZGF0YXNldCwgd2Ugd2lsbCBhcHBseSBvdXIgY29kZSB0byBvdXIgYG55dHNfZGF0YWAuCgpgYGB7cn0KICAgIG55dHNfZGF0YSAlPD4lCiAgICAgICAgICAgICAgICBtdXRhdGUoZWNpZ19vbmx5X2V2ZXIgPSBjYXNlX3doZW4oZWNpZ19ldmVyID09IFRSVUUgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX2V2ZXIgPT0gRkFMU0UgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX2N1cnJlbnQgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfY3VycmVudCA9PSBGQUxTRSB+IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpLAogICAgICAgICAgICAgICAgIGVjaWdfb25seV9jdXJyZW50ID0gY2FzZV93aGVuKGVjaWdfY3VycmVudCA9PSBUUlVFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX2V2ZXIgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfY3VycmVudCA9PSBGQUxTRSB+IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpLAogICAgICAgICAgICAgICBub25fZWNpZ19vbmx5X2V2ZXIgPSBjYXNlX3doZW4obm9uX2VjaWdfZXZlciA9PSBUUlVFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX2V2ZXIgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfY3VycmVudCA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19jdXJyZW50ID09IEZBTFNFIH4gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IEZBTFNFKSwKICAgICAgICAgbm9uX2VjaWdfb25seV9jdXJyZW50ID0gY2FzZV93aGVuKG5vbl9lY2lnX2N1cnJlbnQgPT0gVFJVRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19ldmVyID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX2N1cnJlbnQgPT0gRkFMU0UgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBGQUxTRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vX3VzZSA9IGNhc2Vfd2hlbihub25fZWNpZ19ldmVyID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX2V2ZXIgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfY3VycmVudCA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19jdXJyZW50ID09IEZBTFNFIH5UUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBGQUxTRSkpICU+JQogICAgICAgICAgICAgICAgICAgIG11dGF0ZShHcm91cCA9IGNhc2Vfd2hlbihlY2lnX29ubHlfZXZlciA9PSBUUlVFIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19vbmx5X2N1cnJlbnQgPT0gVFJVRSB+ICJPbmx5IGUtY2lnYXJldHRlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfb25seV9ldmVyID09IFRSVUUgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX29ubHlfY3VycmVudCA9PSBUUlVFIH4gIk9ubHkgb3RoZXIgcHJvZHVjdHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vX3VzZSA9PSBUUlVFIH4gIk5laXRoZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX29ubHlfZXZlciA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfb25seV9jdXJyZW50ID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19vbmx5X2V2ZXIgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX29ubHlfY3VycmVudCA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9fdXNlID09IEZBTFNFIH4gIkNvbWJpbmF0aW9uIG9mIHByb2R1Y3RzIikpCmBgYAoKCkxhc3RseSwgaXQgY2FuIGJlIHZlcnkgaGVscGZ1bCB0byBoYXZlIHRoZSB0b3RhbCBudW1iZXIgb2Ygc3R1ZGVudHMgc3VydmV5ZWQgZWFjaCB5ZWFyLiBXZSBjYW4gZWFzaWx5IGFkZCBhIHZhcmlhYmxlIGZvciB0aGlzIGJ5IHVzaW5nIHRoZSBgYWRkX2NvdW50KClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIFRoaXMgd2lsbCBjcmVhdGUgYSB2YXJpYWJsZSBjYWxsZWQgYG5gIHdoaWNoIHdpbGwgc2hvdyB0aGUgdG90YWwgbnVtYmVyIG9mIHN1cnZleSByZXNwb25zZXMgZm9yIHRoYXQgeWVhci4KCmBgYHtyfQpueXRzX2RhdGEgJTw+JSBhZGRfY291bnQoeWVhcikKCmBgYAoKIyMjIyB7LnNjcm9sbGFibGV9CmBgYHtyfQpnbGltcHNlKG55dHNfZGF0YSkKYGBgCgojIyMgUXVlc3Rpb24gMSAKClJlY2FsbCB0aGF0IHdlIGFyZSBpbnRlcmVzdGVkIGluIGludmVzdGlnYXRpbmcgaG93IHZhcGluZyBwcm9kdWN0IHVzZSBoYXMgY29tcGFyZWQgd2l0aCBvdGhlciB0b2JhY2NvIHVzZSBvdmVyIHRpbWUuIFRvIGFuc3dlciB0aGlzLCB3ZSBmaXJzdCB3YW50IHRvIGdldCBhIHNlbnNlIG9mIGhvdyB0b2JhY2NvIHVzZSBoYXMgY2hhbmdlZCBpbiBnZW5lcmFsIHNpbmNlIDIwMTUuIAoKVG8gY3JlYXRlIGEgdmlzdWFsaXphdGlvbiBvZiBob3cgdG9iYWNjbyB1c2FnZSBoYXMgY2hhbmdlZCBvdmVyIHRpbWUsIHdlIHdpbGwgZmlyc3QgY29udmVydCB0aGUgdXNhZ2UgZGF0YSB0byBhIHBlcmNlbnQgdmFsdWUgZm9yIGVhY2ggeWVhciwgdGVsbGluZyB1cyB3aGF0IHBlcmNlbnQgb2YgcmVzcG9uZGVudHMgZmFsbCBpbnRvIGEgcGFydGljdWxhciB1c2FnZSBjYXRlZ29yeS4gVG8gZG8gdGhpcyB3ZSB3aWxsIHVzZSB0aGUgYGdyb3VwX2J5KClgIGFuZCBgc3VtbWFyaXplKClgIGZ1bmN0aW9ucyBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBUaGlzIHdpbGwgY3JlYXRlIG5ldyB2YXJpYWJsZXMgd2hpY2ggd2Ugd2lsbCBuYW1lIGBFdmVyYCBhbmQgYEN1cnJlbnRgIGJhc2VkIG9uIHRoZSAgcGVyY2VudGFnZXMgb2YgYFRSVUVgIHZhbHVlcyBmb3IgYHRvYmFjY29fZXZlcmAgYW5kIGB0b2JhY2NvX2N1cnJlbnRgIGZvciBlYWNoIHllYXIuIEluIHRoaXMgY2FzZSB0aGUgYG1lYW4oKWAgZnVuY3Rpb24gaXMgdXNlZCB0byBjYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2VzIGJhc2VkIG9uIGFuIGF1dG9tYXRpYyBjb252ZXJzaW9uIHRoYXQgUiBkb2VzIHdoZXJlIGZvciBUUlVFL0ZBTFNFIHZhcmlhYmxlcywgYFRSVUVgIGlzIGdpdmVuIGEgdmFsdWUgb2Ygb25lIGFuZCBgRkFMU0VgIGlzIGdpdmVuIGEgdmFsdWUgb2YgemVyby4gVGhlIG1lYW4gb2YgYSAwLTEgYmluYXJ5IHZhcmlhYmxlIGlzIGp1c3QgdGhlIHBlcmNlbnQgb2YgdGhlIHRpbWUgdGhlIHZhbHVlIGlzIDEuIE5BIHZhbHVlcyBkbyBub3QgY29udHJpYnV0ZSB0byB0aGUgdG90YWwgY291bnQgd2hlbiB3ZSBpbmNsdWRlIHRoZSBhcmd1bWVudCBgbmEucm0gPSBUUlVFYCB0byBvdXIgZnVuY3Rpb24gY2FsbC4gCgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gc2VlIGEgdG95IGV4YW1wbGU6PC9zdW1tYXJ5PgpgYGB7cn0KIyB0aGUgdGVzdCBkYXRhIGhhcyAzIFRSVUUgdmFsdWVzIGFuZCA3IEZBTFNFIHZhbHVlcwp0ZXN0IDwtdGliYmxlKCJ2YXIxIj0gYygiVFJVRSIsICJUUlVFIiwgIlRSVUUiLCByZXAoIkZBTFNFIiwgNykpKQp0ZXN0JTw+JSBtdXRhdGUodmFyMSA9IGFzLmxvZ2ljYWwodmFyMSkpCnRlc3QKCnRlc3QgJT4lIHN1bW1hcml6ZShQZXJjZW50YWdlID0gbWVhbih2YXIxKSoxMDApCgoKI3RoZSB0ZXN0IGRhdGEgaGFzIDMgVFJVRSB2YWx1ZXMsIDMgRkFMU0UgdmFsdWVzLCBhbmQgNCBOQSB2YWx1ZQp0ZXN0IDwtdGliYmxlKCJ2YXIxIj0gYygiVFJVRSIsICJUUlVFIiwgIlRSVUUiLCByZXAoIkZBTFNFIiwgMyksIHJlcCgiTkEiLCA0KSkpCnRlc3QlPD4lIG11dGF0ZSh2YXIxID0gYXMubG9naWNhbCh2YXIxKSkKdGVzdAoKdGVzdCAlPiUgc3VtbWFyaXplKFBlcmNlbnRhZ2UgPSBtZWFuKHZhcjEsIG5hLnJtID0gVFJVRSkqMTAwKQpgYGAKPC9kZXRhaWxzPgoKQW5kIG5vdyBiYWNrIHRvIG91ciBkYXRhOgoKYGBge3J9CgpueXRzX2RhdGEgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoeWVhcikgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXplKEV2ZXIgPSAobWVhbih0b2JhY2NvX2V2ZXIsIG5hLnJtID0gVFJVRSkqMTAwKSwKICAgICAgICAgICAgICAgICAgQ3VycmVudCA9IChtZWFuKHRvYmFjY29fY3VycmVudCwgbmEucm0gPSBUUlVFKSoxMDApKQoKYGBgCgpXZSB3aWxsIHVzZSB0aGUgYHBpdm90X2xvbmdlcmAgZnVuY3Rpb24gdG8gdGFrZSBhbGwgY29sdW1ucyBleGNlcHQgeWVhciAoaW4gdGhpcyBjYXNlIHRoZSBgRXZlcmAgYW5kIGBDdXJyZW50YCBjb2x1bW5zKSwgdG8gY3JlYXRlIGEgY29sdW1uIGNhbGxlZCBgVXNlcmAgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIGN1cnJlbnQgY29sdW1uIG5hbWUgaW5mb3JtYXRpb24gYW5kIGEgY29sdW1uIGNhbGxlZCBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2Agd2hpY2ggd2lsbCBjb250YWluIHRoZSBtZWFuIHBlcmNlbnRhZ2UgdmFsdWVzIHRoYXQgd2UganVzdCBjYWxjdWxhdGVkLiBUaGlzIGNvbnZlcnRzIG91ciBkYXRhIGludG8gYSBmb3JtYXQgY2FsbGVkICJsb25nIiBmb3JtYXQuCgpgYGB7cn0KCm55dHNfZGF0YSAlPiUKICAgIGRwbHlyOjpncm91cF9ieSh5ZWFyKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpemUoRXZlcj0obWVhbih0b2JhY2NvX2V2ZXIsIG5hLnJtID0gVFJVRSkqMTAwKSwKICAgICAgICAgICAgICAgICAgICAgQ3VycmVudD0obWVhbih0b2JhY2NvX2N1cnJlbnQsIG5hLnJtID0gVFJVRSkqMTAwKSklPiUKICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAteWVhciwgbmFtZXNfdG8gPSAiVXNlciIsIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikKCmBgYApZb3UgbWF5IGhhdmUgbm90aWNlZCB0aGF0IG91ciBkYXRhIGlzIGxvbmdlciB0aGFuIGl0IHVzZWQgdG8gYmUhIEhlbmNlIHRoZSBuYW1lIG9mIHRoZSBmdW5jdGlvbiBgcGl2b3RfbG9uZ2VyKClgLiBEYXRhIGlzIG9mdGVuIGVhc2llciB0byBwbG90IHdoZW4gaXQgaXMgaW4gdGhpcyBmb3JtYXQuCiAgCk5vdyB3ZSB3aWxsIHVzZSB0aGlzIGRhdGEgdG8gY3JlYXRlIGEgcGxvdCB1c2luZyB0aGUgYGdncGxvdDJgIHBhY2thZ2UuIAoKVGhlIGZpcnN0IHRoaW5nIHdlIGRvIHRvIGNyZWF0ZSBhIHBsb3QgaXMgc3BlY2lmeSB3aGF0IGRhdGEgd2UgYXJlIHVzaW5nIGZvciBvdXIgeCBheGlzIGFuZCB5IGF4aXMgd2l0aCB0aGVgYWVzKClgIGFyZ3VtZW50IG9mIHRoZSBgZ2dwbG90KClgIGZ1bmN0aW9uLiBUaGVuIHdlIGFkZCBsYXllcnMgdG8gb3VyIHBsb3QgdGhhdCBzcGVjaWZ5IHdoYXQgdHlwZSBvZiBwbG90IHdlIHdvdWxkIGxpa2UgdG8gY3JlYXRlLiBXZSBjYW4gdXNlIHRoZSBgZ2VvbV9saW5lKClgIGZ1bmN0aW9uIHRvIGNyZWF0ZSBsaW5lcyBmb3IgZWFjaCB0eXBlIG9mIHVzZXIuIFdlIHNwZWNpZnkgdGhhdCB3ZSB3YW50IHRvIHVzZSBkaWZmZXJlbnQgbGluZSB0eXBlcyBmb3IgZWFjaCB1c2VyIHVzaW5nIGBhZXMoKWAuIFdlIHdpbGwgYWxzbyBhZGQgcG9pbnRzIHRvIG91ciBsaW5lcyB1c2luZyB0aGUgYGdlb21fcG9pbnQoKWAgZnVuY3Rpb24uIFdlIGNhbiBhZGQgYWRkaXRpb25hbCBsYXllcnMgdG8gc3BlY2lmeSBjb2xvcnMgYW5kIGRldGFpbHMgYWJvdXQgbGFiZWxzIGFuZCBsZWdlbmRzIGV0Yy4KICAKYGBge3J9ICAKICAKcGxvdDEgPC0gbnl0c19kYXRhICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHllYXIpICU+JQogICAgZHBseXI6OnN1bW1hcml6ZShFdmVyPShtZWFuKHRvYmFjY29fZXZlciwgbmEucm0gPSBUUlVFKSoxMDApLAogICAgICAgICAgICAgICAgICAgICBDdXJyZW50PShtZWFuKHRvYmFjY29fY3VycmVudCwgbmEucm0gPSBUUlVFKSoxMDApKSU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLXllYXIsIG5hbWVzX3RvID0gIlVzZXIiLCB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpJT4lCiAgICBnZ3Bsb3QoYWVzKHg9eWVhcix5PWBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCkpICsKICAgIGdlb21fbGluZShhZXMobGluZXR5cGU9VXNlcikpICsgCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFLCBzaXplID0gMikgKwogICMgdGhpcyBhbGxvd3MgdXMgdG8gY2hvb3NlIHdoYXQgdHlwZSBvZiBsaW5lIHdlIHdhbnQgZm9yIGVhY2ggbGluZQogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsMSkpICsKICAjIHRoaXMgYWxsb3dzIHVzIHRvIHNwZWNpZnkgaG93IHRoZSB5LWF4aXMgc2hvdWxkIGFwcGVhcgogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCw3MCxieT0xMCksCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDAsNzAsYnk9MTApLAogICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCw3MCkpICsKICAjdGhpcyBhZGp1c3RzIHRoZSBiYWNrZ3JvdW5kIHN0eWxlIG9mIHRoZSBwbG90CiAgICB0aGVtZV9saW5lZHJhdygpICsKICAjIHRoaXMgbW92ZXMgdGhlIGxlZ2VuZCB0byB0aGUgYm90dG9tIG9mIHRoZSBwbG90IGFuZCByZW1vdmVzIHRoZSB4IGF4aXMgdGl0bGUKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKHRpdGxlID0gIkhvdyBoYXMgdG9iYWNjbyB1c2UgdmFyaWVkIG92ZXIgdGhlIHllYXJzPyIsCiAgICAgICAgIHkgPSAiJSBvZiBzdHVkZW50cyIpCgpwbG90MSAKYGBgCgpOaWNlISBOb3cgd2UgY2FuIHNlZSBob3cgb3ZlcmFsbCB0b2JhY2NvIHVzYWdlIGhhcyBjaGFuZ2VkIHNpbmNlIDIwMTcuIEl0IGFwcGVhcnMgdGhhdCB1c2FnZSBmaXJzdCBkZWNyZWFzZWQgZnJvbSAyMDE1IHRvIDIwMTcgYW5kIHRoZW4gaW5jcmVhc2VkIGEgYml0IHNpbmNlIDIwMTcsIHN1cnBhc3NpbmcgdGhlIGxldmVscyBpbiAyMDE1LgoKV2hhdCBhYm91dCBlLWNpZ2FyZXR0ZSB1c2U/IEhvdyBoYXMgdGhlIHVzYWdlIG9mIGUtY2lnYXJldHRlcyBjaGFuZ2VkIG92ZXIgdGltZT8KCmBgYHtyfQpwbG90MWEgPC0gbnl0c19kYXRhICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHllYXIpICU+JQogICAgZHBseXI6OnN1bW1hcml6ZShFdmVyPShtZWFuKGVjaWdfZXZlciwgbmEucm0gPSBUUlVFKSoxMDApLAogICAgICAgICAgICAgICAgICAgICBDdXJyZW50PShtZWFuKGVjaWdfY3VycmVudCwgbmEucm0gPSBUUlVFKSoxMDApKSU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLXllYXIsIG5hbWVzX3RvID0gIlVzZXIiLCB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpJT4lCiAgICBnZ3Bsb3QoYWVzKHg9eWVhcix5PWBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCkpICsKICAgIGdlb21fbGluZShhZXMobGluZXR5cGU9VXNlcikpICsgCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFLCBzaXplID0gMikgKwogICMgdGhpcyBhbGxvd3MgdXMgdG8gY2hvb3NlIHdoYXQgdHlwZSBvZiBsaW5lIHdlIHdhbnQgZm9yIGVhY2ggbGluZQogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsMSkpICsKICAjIHRoaXMgYWxsb3dzIHVzIHRvIHNwZWNpZnkgaG93IHRoZSB5LWF4aXMgc2hvdWxkIGFwcGVhcgogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCw2MCxieT0xMCksCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgwLDYwLGJ5PTEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLDYwKSkgKwogICN0aGlzIGFkanVzdHMgdGhlIGJhY2tncm91bmQgc3R5bGUgb2YgdGhlIHBsb3QKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICMgdGhpcyBtb3ZlcyB0aGUgbGVnZW5kIHRvIHRoZSBib3R0b20gb2YgdGhlIHBsb3QgYW5kIHJlbW92ZXMgdGhlIHggYXhpcyB0aXRsZQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSAiSG93IGhhcyBlLWNpZ2FyZXR0ZSB1c2UgdmFyaWVkIG92ZXIgdGhlIHllYXJzPyIsCiAgICAgICAgIHkgPSAiJSBvZiBzdHVkZW50cyIpCgpwbG90MWEgCgoKCmBgYApJdCBsb29rcyBsaWtlIHRoZSBzaGFwZSBvZiB0aGUgcGxvdCBpcyB2ZXJ5IHNpbWlsYXIgdG8gdG9iYWNjbyB1c2FnZSBvdmVyYWxsLiBXZSBzZWUgYSBkb3dud2FyZCB0cmVuZCB1bnRpbCAyMDE3IHdoZW4gdGhlIHJhdGUgb2YgYm90aCBjdXJyZW50IGFuZCBldmVyIHVzZXJzIGluY3JlYXNlZC4gUmVjYWxsIHRoYXQgdGhpcyBpcyBpbiBhZ3JlZW1lbnQgd2l0aCB0aGUgYXJ0aWNsZXMgdGhhdCB3ZSByZWZlcmVuY2VkIGVhcmxpZXIuIFdlIGNhbiBzZWUgdGhhdCB0aGUgc2xvcGUgbG9va3Mgc3RlZXBlciBmb3IgZS1jaWdhcmV0dGUgdXNhZ2UgYXMgY29tcGFyZWQgdG8gYWxsIHRvYmFjY28gcHJvZHVjdHMgKGluY2x1ZGluZyBlLWNpZ2FyZXR0ZXMpLgoKCk5vdyBsZXQncyBwbG90IHRoaXMgZGF0YSB0b2dldGhlciBvbiB0aGUgc2FtZSBwbG90LgoKV2Ugd2lsbCBoYXZlIGZvdXIgZ3JvdXBzIChlLWNpZ2FyZXR0ZSBldmVyIHVzZXJzLCBlLWNpZ2FyZXR0ZSBjdXJyZW50IHVzZXJzLCB0b2JhY2NvIGV2ZXIgdXNlcnMsIGFuZCB0b2JhY2NvIGN1cnJlbnQgdXNlcnMpIHRvIHBsb3QsIHRoZXJlZm9yZSwgaXQgd291bGQgYmUgdXNlZnVsIHRvIGFkZCBjb2xvciB0byBvdXIgcGxvdC4gS2VlcCBpbiBtaW5kIHRoYXQgZS1jaWdhcmV0dGUgdXNlcnMgYXJlIGEgc3Vic2V0IG9mIGFueSB0b2JhY2NvIHByb2R1Y3QgdXNlcnMuCgpPbmUgaW1wb3J0YW50IHRoaW5nIHRvIGtlZXAgaW4gbWluZCB3aGVuIGNyZWF0aW5nIHBsb3RzIGlzIHRoYXQgaW5kaXZpZHVhbHMgd2l0aCBjb2xvciBibGluZG5lc3MgbWF5IGhhdmUgYSBkaWZmaWN1bHQgdGltZSBkaXN0aW5ndWlzaGluZyBncm91cHMgd2hlbiBjZXJ0YWluIGNvbG9yIGNob2ljZXMgYXJlIHVzZWQuIAoKT25lIGdyZWF0IG9wdGlvbiBpcyB0byB1c2UgdGhlIGB2aXJpZGlzYCBwYWNrYWdlLCB3aGljaCBvZmZlcnMgY29sb3IgcGFsZXR0ZXMgd2l0aCBjb2xvcnMgdGhhdCBhcmUgc3RpbGwgZGlzdGluZ3Vpc2hhYmxlIGJ5IGluZGl2aWR1YWxzIHdpdGggbW9zdCBmb3JtcyBvZiBjb2xvciBibGluZG5lc3MuIAoKV2UgY2FuIGNob29zZSB3aGljaCBjb2xvcnMgd2Ugd2FudCB0byB1c2UgYnkgdXNpbmcgdGhlIGBzaG93X2NvbCgpYCBmdW5jdGlvbiBvZiB0aGUgYHNjYWxlc2AgcGFja2FnZS4KCkhlcmUgYXJlIHNvbWUgY29sb3Igb3B0aW9uczoKYGBge3J9CgpzY2FsZXM6OiBzaG93X2NvbCh2aXJpZGlzX3BhbCgpKDYpKQp2X2NvbG9ycyA9ICB2aXJpZGlzKDYpW2MoMSw0KV0KYGBgCgpXZSB3aWxsIHNlbGVjdCB0aGUgZmlyc3QgYW5kIGZvdXJ0aCBjb2xvcnMgZm9yIG91ciBwbG90LiBUbyBhZGQgdGhlc2Ugc3BlY2lmaWMgY29sb3JzIHdlIHdpbGwgdXNlIHRoZSBgc2NhbGVfY29sb3JfbWFudWFsKClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZS4KCldlIHdpbGwgY2FsY3VsYXRlIHRoZSBtZWFuIGV2ZXIgYW5kIGN1cnJlbnQgdXNhZ2UgcGVyY2VudGFnZXMgZm9yIHN0dWRlbnRzIHdobyB1c2VkIGUtY2lnYXJldHRlcyBvciBhbnkgdG9iYWNjbyBwcm9kdWN0cyAoaW5jbHVkaW5nIGUtY2lnYXJldHRlcykgZm9yIGVhY2ggeWVhciBhZ2FpbiB1c2luZyB0aGUgYGdyb3VwX2J5KClgIGFuZCBgc3VtbWFyaXplKClgIGZ1bmN0aW9ucy4gV2Ugd2lsbCBhZ2FpbiB1c2UgdGhlIGBwaXZvdF9sb25nZXJgIGZ1bmN0aW9uIHRvIGNvbnZlcnQgb3VyIGRhdGEgdG8gbG9uZyBmb3JtYXQuIFdlIHdpbGwgYWxzbyB1c2UgdGhlIGBzZXBhcmF0ZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyYCBwYWNrYWdlIHRvIGNyZWF0ZSB0d28gdmFyaWFibGVzIGZyb20gb25lIG9mIHRoZSB2YXJpYWJsZXMuIFRoaXMgaXMgZG9uZSBieSBzZXBhcmF0aW5nIGJ5LCBpbiB0aGlzIGNhc2UsIGFuIHVuZGVyc2NvcmUuIAoKCmBgYHtyfQogbnl0c19kYXRhICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHllYXIpICU+JQogICAgZHBseXI6OnN1bW1hcml6ZSgiRXZlcl9BbnkgVG9iYWNjbyBQcm9kdWN0IFxuIChpbmNsdWRpbmcgZS1jaWdhcmV0dGVzKSI9KG1lYW4odG9iYWNjb19ldmVyLCBuYS5ybSA9IFRSVUUpKjEwMCksCiAgICAgICAgICAgICAgICAgICAgICJDdXJyZW50X0FueSBUb2JhY2NvIFByb2R1Y3QgXG4gKGluY2x1ZGluZyBlLWNpZ2FyZXR0ZXMpIj0obWVhbih0b2JhY2NvX2N1cnJlbnQsIG5hLnJtID0gVFJVRSkqMTAwKSwKICAgICAgICAgICAgICAgICAgICAgIkV2ZXJfRS1jaWdhcmV0dGVzIj0obWVhbihlY2lnX2V2ZXIsIG5hLnJtID0gVFJVRSkqMTAwKSwKICAgICAgICAgICAgICAgICAgICAgIkN1cnJlbnRfRS1jaWdhcmV0dGVzIj0obWVhbihlY2lnX2N1cnJlbnQsIG5hLnJtID0gVFJVRSkqMTAwKSklPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC15ZWFyLCBuYW1lc190byA9ICJVc2VyIiwgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiKSU+JQogIHNlcGFyYXRlKFVzZXIsIGludG8gPSBjKCJVc2VyIiwgIlByb2R1Y3QiKSwgc2VwID0gIl8iKSU+JQogIGhlYWQoKQoKCnBsb3QxdCA8LSBueXRzX2RhdGEgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoeWVhcikgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXplKCJFdmVyX0FueSBUb2JhY2NvIFByb2R1Y3QgXG4gKGluY2x1ZGluZyBlLWNpZ2FyZXR0ZXMpIj0obWVhbih0b2JhY2NvX2V2ZXIsIG5hLnJtID0gVFJVRSkqMTAwKSwKICAgICAgICAgICAgICAgICAgICAgIkN1cnJlbnRfQW55IFRvYmFjY28gUHJvZHVjdCBcbiAoaW5jbHVkaW5nIGUtY2lnYXJldHRlcykiPShtZWFuKHRvYmFjY29fY3VycmVudCwgbmEucm0gPSBUUlVFKSoxMDApLAogICAgICAgICAgICAgICAgICAgICAiRXZlcl9FLWNpZ2FyZXR0ZXMiPShtZWFuKGVjaWdfZXZlciwgbmEucm0gPSBUUlVFKSoxMDApLAogICAgICAgICAgICAgICAgICAgICAiQ3VycmVudF9FLWNpZ2FyZXR0ZXMiPShtZWFuKGVjaWdfY3VycmVudCwgbmEucm0gPSBUUlVFKSoxMDApKSU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLXllYXIsIG5hbWVzX3RvID0gIlVzZXIiLCB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpJT4lCiAgc2VwYXJhdGUoVXNlciwgaW50byA9IGMoIlVzZXIiLCAiUHJvZHVjdCIpLCBzZXAgPSAiXyIpJT4lCiAgICBnZ3Bsb3QoYWVzKHg9eWVhcix5PWBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCwgY29sb3IgPSBQcm9kdWN0KSkgKwogICAgZ2VvbV9saW5lKGFlcyhsaW5ldHlwZT1Vc2VyKSkgKyAKICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gRkFMU0UsIHNpemUgPSAyKSArCiAgIyB0aGlzIGFsbG93cyB1cyB0byBjaG9vc2Ugd2hhdCB0eXBlIG9mIGxpbmUgd2Ugd2FudCBmb3IgZWFjaCBsaW5lCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoMiwxKSkgKwogICMgd2Ugd2FudCBwdXJwbGUgYXNzb2NpYXRlZCB3aXRoIGUtY2lnYXJldHRlcyB0byBiZSBjb25zaXN0ZW50IHdpdGggbGF0ZXIgcGxvdHMKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcmV2KHZfY29sb3JzKSkrCiAgIyB0aGlzIGFsbG93cyB1cyB0byBzcGVjaWZ5IGhvdyB0aGUgeS1heGlzIHNob3VsZCBhcHBlYXIKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsNjAsYnk9MTApLAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMCw2MCxieT0xMCksCiAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCw2MCkpICsKICAjdGhpcyBhZGp1c3RzIHRoZSBiYWNrZ3JvdW5kIHN0eWxlIG9mIHRoZSBwbG90CiAgICB0aGVtZV9saW5lZHJhdygpICsKICAjIHRoaXMgbW92ZXMgdGhlIGxlZ2VuZCB0byB0aGUgYm90dG9tIG9mIHRoZSBwbG90IGFuZCByZW1vdmVzIHRoZSB4IGF4aXMgdGl0bGUKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKHRpdGxlID0gIkhvdyBoYXMgdG9iYWNjbyB1c2UgdmFyaWVkIG92ZXIgdGhlIHllYXJzPyIsCiAgICAgICAgIHkgPSAiJSBvZiBzdHVkZW50cyIpCgpwbG90MXQgCgpgYGAKCldlIHNlZSBhbiBpbmNyZWFzZSBpbiBhbGwgY2F0ZWdvcmllcyBzdGFydGluZyBpbiAyMDE3LCBidXQgdGhlIHJhdGUgb2YgaW5jcmVhc2UgaXMgaGlnaGVyIGZvciBzdHVkZW50cyB1c2luZyBvbmx5IGUtY2lnYXJldHRlcyAoY3VycmVudCBvciBldmVyIHVzZXJzKSwgYXMgc2hvd24gYnkgdGhlIGhpZ2hlciBzbG9wZSBvZiB0aGUgZS1jaWdhcmV0dGUgbGluZXMuCgpJbiB0aGUgYWJvdmUgcGxvdHMsIHRoZSAiQW55IHRvYmFjY28gcHJvZHVjdCIgZ3JvdXBzIGluY2x1ZGUgaW5kaXZpZHVhbHMgaW4gdGhlICJFLWNpZ2FyZXR0ZSBvbmx5IiBncm91cHMuIE5vdyBsZXQncyBwbG90IHN0dWRlbnRzIGluIHR3byBtdXR1YWxseSBleGNsdXNpdmUgZ3JvdXBzIG9uIHRoZSBzYW1lIHBsb3Q6IHRob3NlIHdobyByZXBvcnRlZCBlaXRoZXIgdXNpbmcgb25seSBlLWNpZ2FyZXR0ZXMgb3Igb25seSBvdGhlciB0b2JhY2NvIHByb2R1Y3RzIChiZXNpZGVzIGUtY2lnYXJldHRlcyksIGJ1dCBub3QgYm90aC4gCgpXZSB3aWxsIGNhbGN1bGF0ZSB0aGUgbWVhbiBldmVyIGFuZCBjdXJyZW50IHVzYWdlIHBlcmNlbnRhZ2VzIGZvciBzdHVkZW50cyBpbiB0aGVzZSB0d28gbXV0dWFsbHkgZXhjbHVzaXZlIGdyb3VwcywgYWdhaW4gdXNpbmcgdGhlIGBncm91cF9ieSgpYCBmdW5jdGlvbiBhbmQgdGhlIGBzdW1tYXJpemUoKWAgZnVuY3Rpb24uIFdlIHdpbGwgYWdhaW4gdXNlIHRoZSBgcGl2b3RfbG9uZ2VyYCBmdW5jdGlvbiB0byBjb252ZXJ0IG91ciBkYXRhIHRvIGxvbmcgZm9ybWF0LiBXZSB3aWxsIGFsc28gYWdhaW4gdXNlIHRoZSBgc2VwYXJhdGUoKWAgZnVuY3Rpb24gb2YgdGhlIGB0aWR5cmAgcGFja2FnZSB0byBjcmVhdGUgdHdvIHZhcmlhYmxlcyBmcm9tIG9uZSB2YXJpYWJsZS4gVGhpcyBpcyBkb25lIGJ5IHNlcGFyYXRpbmcgYnksIGluIHRoaXMgY2FzZSwgYSBzcGFjZS4gCgpgYGB7cn0KCm55dHNfZGF0YSAlPiUKICAgIGRwbHlyOjpncm91cF9ieSh5ZWFyKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpemUoIkV2ZXJfRS1jaWdhcmV0dGUiPShtZWFuKGVjaWdfb25seV9ldmVyLCBuYS5ybSA9IFRSVUUpKjEwMCksCiAgICAgICAgICAgICAgICAgICAgICJDdXJyZW50X0UtY2lnYXJldHRlIj0obWVhbihlY2lnX29ubHlfY3VycmVudCwgbmEucm0gPSBUUlVFKSoxMDApLAogICAgICAgICAgICAgICAgICAgICAiRXZlcl9Ob24tZS1jaWdhcmV0dGUiID0obWVhbihub25fZWNpZ19vbmx5X2V2ZXIsIG5hLnJtID0gVFJVRSkqMTAwKSwKICAgICAgICAgICAgICAgICAgICAgIkN1cnJlbnRfTm9uLWUtY2lnYXJldHRlIj0obWVhbihub25fZWNpZ19vbmx5X2N1cnJlbnQsIG5hLnJtID0gVFJVRSkqMTAwKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAteWVhciwgbmFtZXNfdG8gPSAiVXNlciIsIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgdGlkeXI6OnNlcGFyYXRlKFVzZXIsIGludG8gPSBjKCJVc2VyIiwgIlByb2R1Y3QiKSwgc2VwID0gIl8iKSAlPiUKICBoZWFkKCkKCnBsb3QxYyA8LSBueXRzX2RhdGEgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoeWVhcikgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXplKCJFdmVyX0UtY2lnYXJldHRlIj0obWVhbihlY2lnX29ubHlfZXZlciwgbmEucm0gPSBUUlVFKSoxMDApLAogICAgICAgICAgICAgICAgICAgICAiQ3VycmVudF9FLWNpZ2FyZXR0ZSI9KG1lYW4oZWNpZ19vbmx5X2N1cnJlbnQsIG5hLnJtID0gVFJVRSkqMTAwKSwKICAgICAgICAgICAgICAgICAgICAgIkV2ZXJfTm9uLWUtY2lnYXJldHRlIiA9KG1lYW4obm9uX2VjaWdfb25seV9ldmVyLCBuYS5ybSA9IFRSVUUpKjEwMCksCiAgICAgICAgICAgICAgICAgICAgICJDdXJyZW50X05vbi1lLWNpZ2FyZXR0ZSI9KG1lYW4obm9uX2VjaWdfb25seV9jdXJyZW50LCBuYS5ybSA9IFRSVUUpKjEwMCkpJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAteWVhciwgbmFtZXNfdG8gPSAiVXNlciIsIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIiklPiUKICBzZXBhcmF0ZShVc2VyLCBpbnRvID0gYygiVXNlciIsICJQcm9kdWN0IiksIHNlcCA9ICJfIikgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9eWVhcix5PWBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCwgY29sb3IgPSBQcm9kdWN0KSkgKwogICAgZ2VvbV9saW5lKGFlcyhsaW5ldHlwZT1Vc2VyKSkgKyAKICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gRkFMU0UsIHNpemUgPSAyKSArCiAgIyB0aGlzIGFsbG93cyB1cyB0byBjaG9vc2Ugd2hhdCB0eXBlIG9mIGxpbmUgd2Ugd2FudCBmb3IgZWFjaCBsaW5lCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoMiwxKSkgKwogICMgdGhpcyBhbGxvd3MgdXMgdG8gc3BlY2lmeSBob3cgdGhlIHktYXhpcyBzaG91bGQgYXBwZWFyCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDMwLGJ5PTEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDAsMzAsYnk9MTApLAogICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsMzApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHZfY29sb3JzKSsKICAjdGhpcyBhZGp1c3RzIHRoZSBiYWNrZ3JvdW5kIHN0eWxlIG9mIHRoZSBwbG90CiAgICB0aGVtZV9saW5lZHJhdygpICsKICAjIHRoaXMgbW92ZXMgdGhlIGxlZ2VuZCB0byB0aGUgYm90dG9tIG9mIHRoZSBwbG90IGFuZCByZW1vdmVzIHRoZSB4IGF4aXMgdGl0bGUKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKHRpdGxlID0gIkhvdyBoYXMgdXNlIG9mIG9ubHkgZS1jaWdhcmV0dGVzIGFuZCBcbiBvbmx5IHRvYmFjY28gcHJvZHVjdHMgYmVzaWRlcyBlLWNpZ2FyZXR0ZXMgdmFyaWVkIG92ZXIgdGltZT8iLAogICAgICAgICB5ID0gIiUgb2Ygc3R1ZGVudHMiKQoKcGxvdDFjCgpgYGAKClZlcnkgaW50ZXJlc3RpbmchIFdlIGNhbiBzZWUgZnJvbSB0aGlzIHBsb3QgdGhhdCB0aGUgcGVyY2VudGFnZSBvZiBzdHVkZW50cyB3aG8gaGFkIGN1cnJlbnRseSB1c2VkIChvciBldmVyIHRyaWVkKSBvbmx5IGUtY2lnYXJldHRlcyBncmVhdGx5IGluY3JlYXNlZCBzdGFydGluZyBpbiAyMDE3LCB3aGlsZSBpbiBjb250cmFzdCB0aGUgcGVyY2VudGFnZSBvZiBzdHVkZW50cyB3aG8gaGFkIGV2ZXIgdHJpZWQgb25seSBub24tZS1jaWdhcmV0dGUgdG9iYWNjbyBwcm9kdWN0cyBhY3R1YWxseSBkaW1pbmlzaGVkIG92ZXIgdGltZS4gSW4gZmFjdCwgd2UgY2FuIHNlZSB0aGF0IGluIDIwMTkgdGhlIHBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMgd2hvIHdlcmUgY3VycmVudCBlLWNpZ2FyZXR0ZSB1c2VycyBzdXJwYXNzZWQgdGhlIHBlcmNlbnRhZ2UgdGhhdCBoYWQgdHJpZWQgYSBub24tZS1jaWdhcmV0dGUgcHJvZHVjdCBldmVuIGp1c3Qgb25jZS4gCgoKUmVjYWxsIHRoYXQgd2UgbWFkZSBhIHZhcmlhYmxlIGNhbGxlZCBgR3JvdXBgIHRoYXQgaWRlbnRpZmllZCBzdHVkZW50cyB3aG8gdXNlZCBlaXRoZXIganVzdCBlLWNpZ2FyZXR0ZSBwcm9kdWN0cywganVzdCBvdGhlciB0b2JhY2NvIHByb2R1Y3RzIChiZXNpZGVzIGUtY2lnYXJldHRlcyksIG9yIHN0dWRlbnRzIHdobyB1c2VkIGJvdGggZS1jaWdhcmV0dGVzIGFuZCBzb21lIG90aGVyIHR5cGUgb2YgdG9iYWNjbyBwcm9kdWN0LgoKYGBge3J9Cm55dHNfZGF0YSAlPiUKICBjb3VudChHcm91cCkKYGBgCgpXZSB3aWxsIG5vdyBtYWtlIGEgcGxvdCBvdmVyIHRpbWUgb2YgZWFjaCBvZiB0aGVzZSBncm91cHMuIFNpbmNlIHdlIHdpbGwgaGF2ZSA0IHRvdGFsIGdyb3Vwcywgd2Ugd2lsbCB1c2UgNCBvZiB0aGUgdmlyaWRpcyBjb2xvcnMuCk5vdGljZSwgdGhhdCBpbiB0aGlzIGNhc2Ugd2UgYXJlIGdyb3VwaW5nIGJ5IHRocmVlIHZhcmlhYmxlcyBieSBzaW1wbHkgc2VwYXJhdGluZyB0aGUgdmFyaWFibGVzIHRoYXQgd2Ugd2FudCB0byBncm91cCBieSB3aXRoIGEgY29tbWEgaW4gb3VyIGBncm91cF9ieSgpYCBmdW5jdGlvbiBsaWtlIHRoaXM6IGBncm91cF9ieShHcm91cCwgeWVhciwgbilgLiAKCmBgYHtyfQoKbnl0c19kYXRhICU+JQogIGdyb3VwX2J5KEdyb3VwLCB5ZWFyLCBuKSAlPiUKICBzdW1tYXJpc2UoZ3JvdXBfY291bnQgPSBuKCkpICU+JQogIG11dGF0ZSgiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIgPSBncm91cF9jb3VudCAvbioxMDApICU+JQogIGhlYWQoKQoKdl9jb2xvcnMgPSAgdmlyaWRpcyg1KVsxOjRdCgpueXRzX2RhdGEgJT4lCiAgZ3JvdXBfYnkoR3JvdXAsIHllYXIsIG4pICU+JQogIHN1bW1hcmlzZShncm91cF9jb3VudCA9IG4oKSkgJT4lCiAgbXV0YXRlKCJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIiA9IGdyb3VwX2NvdW50IC9uKjEwMCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCwgY29sb3IgPSBHcm91cCkpKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpKwogIGdlb21fbGluZSgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdl9jb2xvcnMpKwogIHRoZW1lX2xpbmVkcmF3KCkgKwogIGxhYnMoeCA9ICJZZWFyIikKCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZSBtYWpvcml0eSBvZiBzdHVkZW50cyBkaWQgbm90IHJlcG9ydCB1c2luZyBhbnkgdG9iYWNjbyBwcm9kdWN0cy4gT2YgdGhlIHN0dWRlbnRzIHRoYXQgZGlkIHJlcG9ydCB1c2luZyB0b2JhY2NvIHByb2R1Y3RzLCB0aGUgbWFqb3JpdHkgb2YgdGhlIHN0dWRlbnRzIHVzZWQgYm90aCBlLWNpZ2FyZXR0ZXMgYW5kIHNvbWUgb3RoZXIgdG9iYWNjbyBwcm9kdWN0LiBBZ2FpbiwgYSBtdWNoIGxhcmdlciBwZXJjZW50YWdlIHJlcG9ydGVkIHVzaW5nIG9ubHkgZS1jaWdhcmV0dGVzIHJhdGhlciB0aGFuIG9ubHkgb3RoZXIgdG9iYWNjbyBwcm9kdWN0cyBpbiAyMDE5LgoKV2Ugd2lsbCBmdXJ0aGVyIGV4cGxvcmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGUtY2lnYXJldHRlIHVzYWdlIGFuZCBvdGhlciB0b2JhY2NvIHByb2R1Y3RzIGEgYml0IGxhdGVyIGluIHRoZSBjYXNlIHN0dWR5LgoKCiMjIyBRdWVzdGlvbiAyCgpOb3cgd2Ugd2FudCB0byBsb29rIGhvdyBlLWNpZ2FyZXR0ZSBzbW9raW5nIHJhdGVzIGNvbXBhcmUgYmV0d2VlbiBtYWxlcyBhbmQgZmVtYWxlcyBhY3Jvc3MgdGltZS4gCgoKV2Ugd2lsbCBjYWxjdWxhdGUgdGhlIHBlcmNlbnQgZXZlciBhbmQgY3VycmVudCBlLWNpZ2FyZXR0ZSB1c2VycyBmb3IgZWFjaCB5ZWFyIGFuZCBzZXggY2F0ZWdvcnkgYWdhaW4gdXNpbmcgdGhlIGBncm91cF9ieSgpYCBmdW5jdGlvbiBhbmQgdGhlIGBzdW1tYXJpemUoKWAgZnVuY3Rpb24uICBXZSB3aWxsIGFnYWluIHVzZSB0aGUgYHBpdm90X2xvbmdlcmAgZnVuY3Rpb24gdG8gY29udmVydCBvdXIgZGF0YSB0byBsb25nIGZvcm1hdC4gQmVjYXVzZSB0aGVyZSBhcmUgc29tZSBtaXNzaW5nIHZhbHVlcyBmb3IgdGhlIGBTZXhgIHZhcmlhYmxlLCB3ZSB3aWxsIGZpbHRlciB0aGVzZSBvdXQ7IGJhc2VkIG9uIHRoZSBjb2RlYm9vaywgdGhlcmUgaXMgbGl0dGxlIGluZm9ybWF0aW9uIGFib3V0IHdoeSB0aGVzZSB2YWx1ZXMgYXJlIG1pc3NpbmcsIHNvIG91ciBzdXJ2ZXkgZGF0YSBvbmx5IGFsbG93cyB1cyB0byBjb25zaWRlciB0d28gcmVwb3J0ZWQgc2V4IHZhbHVlcyB3aXRoIGNvbmZpZGVuY2UuCgpBVk9DQURPOiBDYXJyaWUsIEkgYW0gZmlsdGVyaW5nIG91dCB0aGUgTkFzIGZvciBTZXggbm93OyBjYW4geW91IGNoZWNrL21vZGlmeSB0aGUgbGFuZ3VhZ2UgSSBpbmNsdWRlZCBhYm92ZT8gSSBmZWVsIGxpa2UgeW91IHB1dCBpdCBtb3JlIGVsb3F1ZW50bHkgb24gdGhlIHBob25lLiAKCkFWT0NBRE86IEFsc28sIGluIHRoaXMgcGxvdCB0aXRsZSBlLWNpZ2FyZXR0ZSBpcyBjaGFuZ2VkIHRvIHZhcGluZyAtLSBpcyB0aGF0IG9uIHB1cnBvc2U/IFNob3VsZCB3ZSBtYWtlIHRoYXQgY2hhbmdlIGVhcmxpZXIgb3IgdGhyb3VnaG91dCB0aGUgY2FzZSBzdHVkeT8gT3Igc3RpY2sgd2l0aCBlLWNpZ2FyZXR0ZT8KCmBgYHtyfQoKdl9jb2xvcnMgPSAgdmlyaWRpcyg2KVtjKDEsNCldCgpueXRzX2RhdGEgJT4lCiAgICAgZmlsdGVyKCFpcy5uYShTZXgpKSAlPiUKICAgICBncm91cF9ieSh5ZWFyLCBTZXgpICU+JQogICAgIHN1bW1hcml6ZShFdmVyPShtZWFuKEVFTENJR1QsIG5hLnJtID0gVFJVRSkqMTAwKSwKICAgICAgICAgICAgICAgQ3VycmVudD0obWVhbihDRUxDSUdULCBuYS5ybSA9IFRSVUUpKjEwMCkpJT4lCiAgICAgI2ZpbHRlcighaXMubmEoU2V4KSkgJT4lCiAgICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBFdmVyOkN1cnJlbnQsIAogICAgICAgICAgICAgICBuYW1lc190byA9ICJVc2VyIiwgCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgICAgaGVhZCgpCgpwbG90MiA8LSBueXRzX2RhdGEgJT4lCiAgICAgZmlsdGVyKCFpcy5uYShTZXgpKSAlPiUKICAgICBncm91cF9ieSh5ZWFyLCBTZXgpICU+JQogICAgIHN1bW1hcml6ZShFdmVyPShtZWFuKEVFTENJR1QsIG5hLnJtID0gVFJVRSkqMTAwKSwKICAgICAgICAgICAgICAgQ3VycmVudD0obWVhbihDRUxDSUdULCBuYS5ybSA9IFRSVUUpKjEwMCkpJT4lCiAgICAjIGZpbHRlcighaXMubmEoU2V4KSkgJT4lCiAgICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBFdmVyOkN1cnJlbnQsIAogICAgICAgICAgICAgICBuYW1lc190byA9ICJVc2VyIiwgCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLHkgPWBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCwgY29sb3IgPSBTZXgpKSArCiAgICBnZW9tX2xpbmUoYWVzKGxpbmV0eXBlID0gVXNlcikpICsgCiAgICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gRkFMU0UsIHNpemUgPSAyKSArCiAgICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygyLDEpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID12X2NvbG9ycykrCiAgICB0aGVtZV9saW5lZHJhdygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAojICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKHRpdGxlID0gIkhvdyBkbyB2YXBpbmcgcmF0ZXMgY29tcGFyZSBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzPyIsCiAgICAgICAgIHN1YnRpdGxlID0gIkN1cnJlbnQgYW5kIGV2ZXIgdXNlcnMgYnkgc2V4IiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnBsb3QyCmBgYAoKSXQgbG9va3MgbGlrZSB0aGUgcmF0ZXMgYXJlIGZhaXJseSBzaW1pbGFyIGJldHdlZW4gdGhlIHNleGVzLCBob3dldmVyIHRoZSByYXRlIGZvciBtYWxlcyBhcHBlYXJzIHRvIGJlIGNvbnNpc3RlbnRseSBoaWdoZXIgYWNyb3NzIHRpbWUuCgoKIyMjIFF1ZXN0aW9uIDMKCldlIGFyZSBhbHNvIGludGVyZXN0ZWQgaW4gd2hhdCB2YXBpbmcgYnJhbmRzIGFuZCBmbGF2b3JzIGFwcGVhciB0byBiZSB1c2VkIHRoZSBtb3N0IGZyZXF1ZW50bHkuIE9ubHkgdGhlIDIwMTkgZGF0YSBzZXQgaGFzIHRoaXMgaW5mb3JtYXRpb24uIFRoZXJlZm9yZSwgd2Ugd2lsbCBmaWx0ZXIgZm9yIGp1c3QgdGhpcyB5ZWFyIHVzaW5nIHRoZSBgZmlsdGVyKClgIGZ1bmN0aW9uIG9mICB0aGUgYGRwbHlyYCBwYWNrYWdlLiBXZSB3aWxsIHVzZSB0aGUgYHN1bW1hcml6ZSgpYCBmdW5jdGlvbiBzbGlnaHRseSBkaWZmZXJlbnRseSB0aGlzIHRpbWUsIHRvIGNhbGN1bGF0ZSB0aGUgdG90YWwgbnVtYmVyIG9mIHN0dWRlbnRzIHVzaW5nIGVhY2ggYnJhbmQgdXNpbmcgdGhlIGBuKClgIGZ1bmN0aW9uIGFuZCB0aGUgYHN1bSgpYCBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIHBlcmNlbnQgZm9yIGVhY2ggYnJhbmQgYmFzZWQgb24gdGhlIGNvdW50cy4gV2Ugd2lsbCBhbHNvIHJlb3JkZXIgdGhlIGZhY3RvciBsZXZlbHMgZm9yIHRoZSBicmFuZCBuYW1lcyBzbyB0aGF0IHRoZXkgYXJlIGluIGRlc2NlbmRpbmcgb3JkZXIgb2YgcGVyY2VudCB1c2UsIHVzaW5nIHRoZSBgZmN0X3Jlb3JkZXIoKWAgZnVuY3Rpb24gZnJvbSBgZHBseXJgLiBUaGlzIHdpbGwgbWFrZSB0aGVtIGFwcGVhciBpbiBkZWNyZWFzaW5nIG9yZGVyIG9mIHBlcmNlbnQgdXNlIG9uIHRoZSBwbG90LgoKV2Ugd2lsbCBtYWtlIGEgYmFyIHBsb3QgdGhpcyB0aW1lIGJ5IHVzaW5nIGBnZW9tX2JhcmAuIEltcG9ydGFudGx5IHdlIGFzc2lnbiB0aGUgYHN0YXRgIGFyZ3VtZW50IHRvIGBpZGVudGl0eWAsIHNvIHRoYXQgd2UgYXJlIHVzaW5nIHRoZSBwZXJjZW50YWdlcyB0aGF0IHdlIGNhbGN1bGF0ZWQgbm90IHRoZSBjb3VudHMgd2hpY2ggaXMgd2hhdCBpcyB1c2VkIGJ5IGRlZmF1bHQuIFdoZW4gY29sb3IgaW4gc3BlY2lmaWVkIG91dHNpZGUgb2YgdGhlIGBhZXMoKWAgYXJndW1lbnQsIHRoaXMgZGV0ZXJtaW5lcyB0aGUgYm9yZGVyIGNvbG9yIG9mIHRoZSBiYXJzLCB3aGljaCBpbiB0aGlzIGNhc2Ugd2lsbCBiZSBibGFjay4KCmBgYHtyfQoKIG55dHNfZGF0YSAlPiUKICAgIGZpbHRlcih5ZWFyPT0yMDE5KSAlPiUKICAgIGdyb3VwX2J5KGJyYW5kX2VjaWcpICU+JQogICAgZmlsdGVyKCFpcy5uYShicmFuZF9lY2lnKSkgJT4lCiAgc3VtbWFyaXplKG4gPSBuKCkpICU+JQogICAgbXV0YXRlKHRvdGFsID0gc3VtKG4pLAogICAgICAgICAgIFBlcmNlbnQgPSBuKjEwMC90b3RhbCkgJT4lCiAgICBtdXRhdGUoYnJhbmRfZWNpZyA9IGZjdF9yZW9yZGVyKGJyYW5kX2VjaWcsIGRlc2MoUGVyY2VudCkpKQoKCnBsb3QzIDwtIG55dHNfZGF0YSAlPiUKICAgIGZpbHRlcih5ZWFyPT0yMDE5KSAlPiUKICAgIGdyb3VwX2J5KGJyYW5kX2VjaWcpICU+JQogICAgZmlsdGVyKCFpcy5uYShicmFuZF9lY2lnKSkgJT4lCiAgc3VtbWFyaXplKG4gPSBuKCkpICU+JQogICAgbXV0YXRlKHRvdGFsID0gc3VtKG4pLAogICAgICAgICAgIFBlcmNlbnQgPSBuKjEwMC90b3RhbCkgJT4lCiAgICBtdXRhdGUoYnJhbmRfZWNpZyA9IGZjdF9yZW9yZGVyKGJyYW5kX2VjaWcsIGRlc2MoUGVyY2VudCkpKSAlPiUKICAgIGdncGxvdChhZXMoeD1icmFuZF9lY2lnLHk9UGVyY2VudCwgZmlsbD1icmFuZF9lY2lnKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSAiV2hhdCB2YXBpbmcgYnJhbmRzIGFwcGVhciB0byBiZSB1c2VkIHRoZSBtb3N0IGZyZXF1ZW50bHk/IiwKICAgICAgICAgc3VidGl0bGUgPSAiQnJhbmQgb2YgZS1jaWdhcmV0dGUgbW9zdCBmcmVxdWVudGx5IHVzZWQgaW4gdGhlIGxhc3QgMzAgZGF5cyAoMjAxOSkiLAogICAgICAgICB5ID0gIiUgb2YgZS1jaWdhcmV0dGUgdXNlcnMgcmVzcG9uZGluZyIpCgpwbG90MwpgYGAKCkp1dWwgYXBwZWFycyB0byBiZSB0aGUgbW9zdCB3aWRlbHkgdXNlZCBicmFuZC4gVGhpcyBpcyBpbiBhZ3JlZW1lbnQgd2l0aCBhIHJlY2VudCBbYXJ0aWNsZV0oaHR0cHM6Ly90b2JhY2NvY29udHJvbC5ibWouY29tL2NvbnRlbnQvdG9iYWNjb2NvbnRyb2wvMjgvMi8xNDYuZnVsbC5wZGYpLCB3aG9zZSBtb3N0IHJlY2VudCBkYXRhIHdhcyBmcm9tIDIwMTc6CgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmNhcD0iSHVhbmcgSiwgRHVhbiBaLCBLd29rIEosIGV0IGFsLiBUb2IgQ29udHJvbCAyMDE5OzI4OjE0NuKAkzE1MS4iLCBvdXQud2lkdGggPSAnMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJIdWFuZ0pfRHVhblpfS3dva0pfZXRfYWxfVG9iYWNjb0NvbnRyb2xfRmlndXJlMS5wbmciKSkKYGBgCgpXZSBhcmUgYWxzbyBpbnRlcmVzdGVkIGluIGhvdyB0aGUgdXNhZ2Ugb2YgZGlmZmVyZW50IGZsYXZvcnMgaGFzIGNoYW5nZWQgb3ZlciB0aW1lLiAKCgpUbyBldmFsdWF0ZSB0aGlzIHdlIHdpbGwgY2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIG9mIHN0dWRlbnRzIHVzaW5nIGVhY2ggZmxhdm9yIGVhY2ggeWVhciAtIHRoaXMgaW5jbHVkZXMgdXNhZ2Ugb2YgYW55IHR5cGUgb2YgZmxhdm9yZWQgdG9iYWNjbyBwcm9kdWN0LiBXZSB3aWxsIGV4Y2x1ZGUgMjAxNSBkYXRhLCBhcyBubyBzcGVjaWZpYyBmbGF2b3IgcXVlc3Rpb25zIHdlcmUgYXNrZWQgYXQgdGhhdCB0aW1lLgoKUmVjYWxsIHRoYXQgYE5BYCB2YWx1ZXMgYXJlIG5vdCBpbmNsdWRlZCBpbiBjYWxjdWxhdGluZyB0aGUgdG90YWwgY291bnQgZm9yIG91ciBwZXJjZW50YWdlcy4gSG93ZXZlciBhbGwgb2YgdGhlc2UgZmxhdm9yIHF1ZXN0aW9ucyBoYWQgY29tcGxldGUgcmVwb3J0aW5nIGFuZCBkaWQgbm90IGhhdmUgYE5BYCB2YWx1ZXMuIFRoZXJlZm9yZSwgdGhlc2UgdmFsdWVzIHJlZmxlY3QgdGhlIHBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMgcmVwb3J0aW5nIHVzaW5nIGEgcGFydGljdWxhciBmYXZvciBvdXQgb2YgYWxsIHN0dWRlbnRzIHN1cnZleWVkIChpbmNsdWRpbmcgdGhvc2UgdGhhdCBkaWQgbm90IHVzZSBhbnkgdG9iYWNjbyBwcm9kdWN0cykuIEFsc28gc3R1ZGVudHMgd2VyZSBhbGxvd2VkIHRvIHNlbGVjdCBtb3JlIHRoYW4gb25lIGZsYXZvci4gWW91IGNhbiBzZWUgd2hldGhlciB0aGVzZSB2YXJpYWJsZXMgaGFkIGNvbXBsZXRlIHJlcG9ydGluZyBieSBjaGVja2luZyB0aGUgYE5BYCB2YWx1ZXMgdXNpbmcgdGhlIGJhc2UgYHN1bW1hcnlgIGZ1bmN0aW9uLiBBbHRlcm5hdGl2ZWx5IHlvdSBjYW4gY3JlYXRlIGEgdmlzdWFsIHJlcHJlc2VudGF0aW9uIHVzaW5nIHRoZSBgdmlzX21pc3MoKWAgZnVuY3Rpb24gb2YgdGhlIGBuYW5pYXJgIHBhY2thZ2UuCgojIyMjIHsuc2Nyb2xsYWJsZX0KYGBge3J9CiMgU2Nyb2xsIHRocm91Z2ggdGhlIG91dHB1dCEKbnl0c19kYXRhICU+JSAKICBmaWx0ZXIoeWVhciE9MjAxNSkgJT4lIAogIHN1bW1hcnkoKQoKYGBgCiMjIyMKCgpgYGB7cn0Kbnl0c19kYXRhICU+JQogIGZpbHRlcih5ZWFyIT0yMDE1KSAlPiUKICBzZWxlY3QobWVudGhvbDphbGNvaG9saWNfZHJpbmspJT4lCiAgdmlzX21pc3MoKQoKYGBgCgpUaGUgcGxvdCBhYm92ZSBjb25maXJtcyB0aGF0IHRoZXNlIHZhcmlhYmxlcyBoYXZlIG5vIGBOQWAgdmFsdWVzIChiZWNhdXNlIGFsbCBmaWVsZHMgaW5kaWNhdGUgMTAwJSBvZiBkYXRhIGlzIHByZXNlbnQpLgoKYGBge3J9CnBsb3Q0IDwtIG55dHNfZGF0YSAlPiUKICBmaWx0ZXIoeWVhciE9MjAxNSkgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgICAgIHN1bW1hcml6ZShNZW50aG9sID0gKG1lYW4obWVudGhvbCkqMTAwKSwKICAgICAgIGBDbG92ZSBvciBTcGljZWAgPSAobWVhbihjbG92ZV9zcGljZSkqMTAwKSwKICAgICAgICAgICAgICAgICAgRnJ1aXQgPSAobWVhbihmcnVpdCkqMTAwKSwKICAgICAgICAgICAgICBDaG9jb2xhdGUgPSAobWVhbihjaG9jb2xhdGUpKjEwMCksCiAgICAgIGBBbGNvaG9saWMgRHJpbmtgID0gKG1lYW4oYWxjb2hvbGljX2RyaW5rKSoxMDApLApgQ2FuZHkvRGVzc2VydHMvU3dlZXRzYCA9IChtZWFuKGNhbmR5X2Rlc3NlcnRfc3dlZXRzKSoxMDApLAogICAgICAgICAgICAgICAgICBPdGhlciA9IChtZWFuKG90aGVyKSoxMDApKSAlPiUKICAgICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtIHllYXIsIG5hbWVzX3RvID0gIkZsYXZvciIsIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgcmVuYW1lKFllYXIgPSB5ZWFyKSAlPiUKCiBnZ3Bsb3QoYWVzKHkgPSBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2AsIAogICAgICAgICAgICB4ID0gWWVhciwgCiAgICAgICAgIGZpbGwgPSByZW9yZGVyKEZsYXZvciwgYFBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHNgKSkpKwpnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCBjb2xvciA9ICJibGFjayIpKwogIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZT1UUlVFKSsKICB0aGVtZV9saW5lZHJhdygpICsKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQoIkZsYXZvciIpKSsKICBsYWJzKHRpdGxlID0gIldoYXQgZmxhdm9ycyBhcHBlYXIgdG8gYmUgdXNlZCB0aGUgbW9zdCBmcmVxdWVudGx5PyIsCiAgICAgICBzdWJ0aXRsZSA9ICJGbGF2b3JzIG9mIHRvYmFjY28gcHJvZHVjdHMgdXNlZCBpbiB0aGUgcGFzdCAzMCBkYXlzIikKCnBsb3Q0IApgYGAKCkZyb20gdGhpcyBwbG90LCB3ZSBjYW4gc2VlIHRoYXQgZnJ1aXQgZmxhdm9ycyBhcmUgdGhlIG1vc3Qgd2lkZWx5IHVzZWQgcHJvZHVjdHMsIGZvbGxvd2VkIGJ5IG1lbnRob2wgb3IgbWludCBmbGF2b3JlZCBwcm9kdWN0cy4gV2UgY2FuIGFsc28gc2VlIHRoYXQgdGhlcmUgd2FzIGEgZ2VuZXJhbCBpbmNyZWFzZSBpbiB0aGUgdXNhZ2Ugb2YgZmxhdm9yZWQgcHJvZHVjdHMgb3ZlciB0aW1lLgoKV2Ugd2lsbCBub3cgbG9vayBzcGVjaWZpY2FsbHkgYXQgdGhlIHVzYWdlIG9mIGZsYXZvcmVkIGUtY2lnYXJldHRlIHByb2R1Y3RzIHZzIG90aGVyIGZsYXZvcmVkIHRvYmFjY28gcHJvZHVjdHMuIAoKUmVjYWxsIHRoYXQgd2UgbWFkZSBhIHZhcmlhYmxlIGNhbGxlZCBgR3JvdXBgIHRoYXQgaWRlbnRpZmllZCBzdHVkZW50cyB3aG8gdXNlZCBlaXRoZXIganVzdCBlLWNpZ2FyZXR0ZS92YXBpbmcgcHJvZHVjdHMsIGp1c3Qgb3RoZXIgdG9iYWNjbyBwcm9kdWN0cyAoYmVzaWRlcyBlLWNpZ2FyZXR0ZXMpLCBvciBzdHVkZW50cyB3aG8gdXNlZCBib3RoIGUtY2lnYXJldHRlcyBhbmQgc29tZSBvdGhlciB0eXBlIG9mIHRvYmFjY28gcHJvZHVjdC4gV2Ugd2lsbCBjb21wYXJlIHRoZSB1c2FnZSBvZiB0aGVzZSBmbGF2b3JzIGZvciB0aGVzZSBkaWZmZXJlbnQgZ3JvdXBzLiBXZSBhbHNvIHBlcmZvcm0gc29tZSBkYXRhIHN1bW1hcmllcyB0byBkZWNpZGUgaG93IHRvIG9yZGVyIHRoZSBwYW5lbHMgKGZsYXZvcnMpIGZvciBkaXNwbGF5LgoKCgpgYGB7cn0KCnZfY29sb3JzID0gIHZpcmlkaXMoNSlbMTo0XQoKcGxvdDUgPC0gbnl0c19kYXRhICU+JQogIGZpbHRlcih5ZWFyICE9IDIwMTUpICU+JQogIGdyb3VwX2J5KHllYXIsIEdyb3VwKSAlPiUKICAgICAgICBzdW1tYXJpemUoTWVudGhvbCA9IChtZWFuKG1lbnRob2wpKjEwMCksCiAgICAgICAgIGBDbG92ZSBvciBTcGljZWAgPSAobWVhbihjbG92ZV9zcGljZSkqMTAwKSwKICAgICAgICAgICAgICAgICAgICBGcnVpdCA9IChtZWFuKGZydWl0KSoxMDApLAogICAgICAgICAgICAgICAgQ2hvY29sYXRlID0gKG1lYW4oY2hvY29sYXRlKSoxMDApLAogICAgICAgIGBBbGNvaG9saWMgRHJpbmtgID0gKG1lYW4oYWxjb2hvbGljX2RyaW5rKSoxMDApLAogIGBDYW5keS9EZXNzZXJ0cy9cblN3ZWV0c2AgPSAobWVhbihjYW5keV9kZXNzZXJ0X3N3ZWV0cykqMTAwKSwKICAgICAgICAgICAgICAgICAgICBPdGhlciA9IChtZWFuKG90aGVyKSoxMDApLAogICAgICAgICAgICAgIFJlc3BvbmRlbnRzID0gbigpKSAlPiUKICAjY29udmVydGluZyBhbGwgY29sdW1ucyBiZXR3ZWVuIGFuZCBpbmNsdWRpbmcgTWVudGhvbCBhbmQgT3RoZXIgdG8gb25lIGNvbHVtbiBjYWxsZWQgRmxhdm9yCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBNZW50aG9sOk90aGVyLCBuYW1lc190byA9ICJGbGF2b3IiLCB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpICU+JQogIGdyb3VwX2J5KEZsYXZvcikgJT4lCiAgIyBjYWxjdWxhdGUgdGhlIGNvdW50IG9mIHN0dWRlbnRzIGluIHRoZSB5ZWFyL2dyb3VwIGNvbWJpbmF0aW9uIHdobyB1c2VkIHRoYXQgZmxhdm9yCiAgbXV0YXRlKGFmZmlybWF0aXZlPShSZXNwb25kZW50cyAqIGBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCkvMTAwKSAlPiUKICAjIGNhbGN1bGF0ZSB0aGUgZnJhY3Rpb24gb2YgdG90YWwgcmVzcG9uZGVudHMgd2hvIHVzZWQgdGhhdCBmbGF2b3IKICBtdXRhdGUoZmxhdm9yX21lYW4gPSBzdW0oYWZmaXJtYXRpdmUpL3N1bShSZXNwb25kZW50cykpICU+JQogIHVuZ3JvdXAoKSAlPiUKICAjIHJlb3JkZXIgdGhlIGxldmVscyBvZiBGbGF2b3IgdG8gYmUgaW4gaW5jcmVhc2luZyBvcmRlciBvZiBwZXJjZW50IG9mIHN0dWRlbnRzIHdobyB1c2VkIHRoYXQgZmxhdm9yCiAgbXV0YXRlKGZsYXZvcl9tZWFuX3JhbmsgPSBkZW5zZV9yYW5rKGZsYXZvcl9tZWFuKSwKICAgICAgICAgRmxhdm9yID0gZmN0X3Jlb3JkZXIoRmxhdm9yLCBmbGF2b3JfbWVhbl9yYW5rKSkgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9YFBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHNgLCBjb2xvcj1Hcm91cCkpICsKICBmYWNldF9ncmlkKH5GbGF2b3IpKwogIGdlb21fbGluZSgpICsgCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFLCBzaXplID0gMikgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdl9jb2xvcnMpICsKICB0aGVtZV9saW5lZHJhdygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwKICAgICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhY2UgPSAiYm9sZCIpKSArIAogIGxhYnModGl0bGUgPSAiQW1vbmcgZGlmZmVyZW50IHByb2R1Y3QgdXNlcnMsIHdoYXQgZmxhdm9ycyBhcmUgbW9zdCBmcmVxdWVudGx5IHVzZWQ/IikKCnBsb3Q1CmBgYAoKCldlIGNhbiBzZWUgZnJvbSB0aGlzIHBsb3QgdGhhdCB0aGVyZSBoYXMgYmVlbiBhbiBpbmNyZWFzZSBpbiB0aGUgbnVtYmVyIG9mIHN0dWRlbnRzIHJlcG9ydGluZyB1c2luZyBmbGF2b3JlZCB0b2JhY2NvIHByb2R1Y3RzLiBVc2VycyB3aG8gdXNlIGJvdGggZS1jaWdhcmV0dGVzIGFuZCBvdGhlciB0b2JhY2NvIHByb2R1Y3RzIGFwcGVhciB0byByZXBvcnQgdXNpbmcgZmxhdm9yZWQgcHJvZHVjdHMgdGhlIG1vc3QsIGZvbGxvd2VkIGJ5IHVzZXJzIHdobyBvbmx5IHVzZSBlLWNpZ2FyZXR0ZXMuCgojIyMgUXVlc3Rpb24gNAoKSXMgdGhlcmUgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiB2YXBpbmcgcmF0ZXMgYW5kIHRvYmFjY28gdXNlPyBOb3cgd2Ugd2lsbCBpbnZlc3RpZ2F0ZSB0aGUgdXNhZ2Ugb2YgZS1jaWdhcmV0dGVzIGNvbXBhcmVkIHRvIG90aGVyIHRvYmFjY28gcHJvZHVjdHMgaW4gZ3JlYXRlciBkZXB0aC4gCgpGaXJzdCBsZXQncyB0YWtlIGEgbG9vayBhdCBob3cgZS1jaWdhcmV0dGUgdXNhZ2UgYW5kIGNpZ2FyZXR0ZSB1c2FnZSBjb21wYXJlLiBXZSB3aWxsIHNlbGVjdCB0aGUgZGF0YSB0aGF0IHNwZWNpZmljYWxseSBoYXMgdG8gZG8gd2l0aCB0aGVzZSBwcm9kdWN0cy4KCmBgYHtyfQoKCnZfY29sb3JzID0gIHZpcmlkaXMoNilbYygxLDQpXQoKbnl0c19kYXRhICU+JQogICAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgICBzdW1tYXJpemUoIkNpZ2FyZXR0ZXMsIEV2ZXIiID0gKG1lYW4oRUNJR1QsIG5hLnJtID0gVFJVRSkqMTAwKSwKICAgICAgICAgICAgIkUtY2lnYXJldHRlcywgRXZlciIgPSAobWVhbihFRUxDSUdULCBuYS5ybSA9IFRSVUUpKjEwMCksCiAgICAgICAgICAgIkNpZ2FyZXR0ZXMsIEN1cnJlbnQiID0gKG1lYW4oQ0NJR1QsIG5hLnJtID0gVFJVRSkqMTAwKSwKICAgICAgICAgIkUtY2lnYXJldHRlcywgQ3VycmVudCIgPSAobWVhbihDRUxDSUdULCBuYS5ybSA9IFRSVUUpKjEwMCkpICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHM9IC15ZWFyLCBuYW1lc190byA9ICJDYXRlZ29yeSIsIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgICBzZXBhcmF0ZSggQ2F0ZWdvcnksIGludG89IGMoIlByb2R1Y3QiLCAiVXNlciIpLCBzZXAgPSAiLCAiKSAlPiUKICAgIGhlYWQoKQoKCnBsb3Q2IDwtIG55dHNfZGF0YSAlPiUKICAgIGdyb3VwX2J5KHllYXIpICU+JQogICAgc3VtbWFyaXplKCJDaWdhcmV0dGVzLCBFdmVyIiA9IChtZWFuKEVDSUdULCBuYS5ybSA9IFRSVUUpKjEwMCksCiAgICAgICAgICAgICJFLWNpZ2FyZXR0ZXMsIEV2ZXIiID0gKG1lYW4oRUVMQ0lHVCwgbmEucm0gPSBUUlVFKSoxMDApLAogICAgICAgICAgICJDaWdhcmV0dGVzLCBDdXJyZW50IiA9IChtZWFuKENDSUdULCBuYS5ybSA9IFRSVUUpKjEwMCksCiAgICAgICAgICJFLWNpZ2FyZXR0ZXMsIEN1cnJlbnQiID0gKG1lYW4oQ0VMQ0lHVCwgbmEucm0gPSBUUlVFKSoxMDApKSAlPiUKICAgIHBpdm90X2xvbmdlcihjb2xzPSAteWVhciwgbmFtZXNfdG8gPSAiQ2F0ZWdvcnkiLCB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpJT4lCiAgICBzZXBhcmF0ZSggQ2F0ZWdvcnksIGludG89IGMoIlByb2R1Y3QiLCAiVXNlciIpLCBzZXAgPSAiLCAiKSAlPiUKICAgIGdncGxvdChhZXMoeD15ZWFyLHk9YFBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHNgLCBjb2xvciA9IFByb2R1Y3QsIGxpbmV0eXBlID0gVXNlcikpICsKICAgIGdlb21fbGluZSgpICsgCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFLCBzaXplID0gMikgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsMSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdl9jb2xvcnMpICsKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSAiSG93IGRvZXMgZS1jaWdhcmV0dGUgdXNlIGNvbXBhcmUgdG8gY2lnYXJldHRlIHVzZT8iLAogICAgICAgICBzdWJ0aXRsZSA9ICJDdXJyZW50IGFuZCBldmVyIHVzZXJzIG9mIGUtY2lnYXJldHRlcyBhbmQgY2lnYXJldHRlcyIsCiAgICAgICAgIHkgPSAiJSBvZiBzdHVkZW50cyIpCgpwbG90NgpgYGAKCkludGVyZXN0aW5nISB3ZSBjYW4gc2VlIHRoYXQgaW4gMjAxOSB0aGUgcGVyY2VudGFnZSBvZiBzdHVkZW50cyB0aGF0IHJlcG9ydGVkIGN1cnJlbnRseSB1c2luZyBlLWNpZ2FyZXR0ZXMgaGFkIHN1cnBhc3NlZCB0aG9zZSB0aGF0IGV2ZXIgdHJpZWQgKGV2ZW4ganVzdCBvbmNlKSBhIGNpZ2FyZXR0ZS4gT3ZlcmFsbCBjaWdhcmV0dGUgdXNhZ2UgYXBwZWFycyB0byBiZSBkZWNsaW5pbmcgb3ZlciB0aW1lLiBUaGlzIGlzIG5vdCB0aGUgY2FzZSBmb3IgZS1jaWdhcmV0dGVzLgoKCk5vdyB3ZSB3aWxsIGxvb2sgYXQgc3R1ZGVudHMgd2hvIHJlcG9ydGVkIHRoYXQgdGhleSBoYWQgZXZlciB0cmllZCBlLWNpZ2FyZXR0ZXMgb3Igbm9uLWNpZ2FyZXR0ZSBwcm9kdWN0cy4gSW4gdGhpcyBjYXNlIHdlIHdpbGwgbm90IHNlcGFyYXRlIG91dCB1c2VycyB3aG8gc3BlY2lmaWNhbGx5IG9ubHkgdXNlZCBvbmUgb3IgdGhlIG90aGVyLiBUaGVyZWZvcmUsIHRoZSBzdHVkZW50cyBpbmNsdWRlZCBpbiB0aGlzIHBsb3Qgd2hvIHJlcG9ydGVkIGFzIGhhdmluZyBldmVyIHRyaWVkIGUtY2lnYXJldHRlcyBtaWdodCBhbHNvIGJlICBjdXJyZW50IHVzZXJzIG9mIG5vbi1lLWNpZ2FyZXR0ZSBwcm9kdWN0cyBvciBtYXkgaGF2ZSBhdCBsZWFzdCB0cmllZCBub24tZS1jaWdhcmV0dGUgcHJvZHVjdHMuCgoKYGBge3J9Cgp2X2NvbG9ycyA9ICB2aXJpZGlzKDYpW2MoMSw0KV0KCnBsb3Q3IDwtIG55dHNfZGF0YSAlPiUKICAgIGdyb3VwX2J5KHllYXIpICU+JQogICAgICBzdW1tYXJpemUoYGUtY2lnYXJldHRlX2V2ZXJgPSAobWVhbihlY2lnX2V2ZXIsIG5hLnJtID0gVFJVRSkqMTAwKSwKICAgICAgICAgICAgYG5vbi1lLWNpZ2FyZXR0ZV9ldmVyYD0gKG1lYW4obm9uX2VjaWdfZXZlciwgbmEucm0gPSBUUlVFKSoxMDApKSAlPiUKICAgIHBpdm90X2xvbmdlcihjb2xzID0gLXllYXIsIG5hbWVzX3RvID0gIkNhdGVnb3J5IiwgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiKSAlPiUKICAgIHNlcGFyYXRlKENhdGVnb3J5LCBpbnRvID0gYygiUHJvZHVjdCIsICJVc2VyIiksIHNlcCA9ICJfIikgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9eWVhcix5PWBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCwgY29sb3I9UHJvZHVjdCkpICsKICAgIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gRkFMU0UsIHNpemUgPSAyKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHZfY29sb3JzKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA2MCwgYnkgPSAxMCksIGxpbWl0cyA9IGMoMCw2MCkpICsKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSAiSG93IGRvZXMgdGhlIHJhdGUgb2YgZXZlciB0cnlpbmcgZS1jaWdhcmV0dGVzIFxuY29tcGFyZSB0byBldmVyIHRyeWluZyBvdGhlciBwcm9kdWN0cyBvdmVyIHRpbWU/IiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnBsb3Q3CmBgYAoKCk5vdyB3ZSB3aWxsIGRvIHRoZSBzYW1lLCBidXQgZm9yIHN0dWRlbnRzIHdobyByZXBvcnRlZCBjdXJyZW50bHkgdXNpbmcgZS1jaWdhcmV0dGVzIG9yIG5vbi1lLWNpZ2FyZXR0ZSBwcm9kdWN0cy4gCgoKYGBge3J9CnZfY29sb3JzID0gIHZpcmlkaXMoNilbYygxLDQpXQoKcGxvdDggPC0gbnl0c19kYXRhICU+JQogICAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgICAgIHN1bW1hcml6ZShgZS1jaWdhcmV0dGVfY3VycmVudGA9IChtZWFuKGVjaWdfY3VycmVudCwgbmEucm0gPSBUUlVFKSoxMDApLAogICAgICAgICAgICBgbm9uLWUtY2lnYXJldHRlX2N1cnJlbnRgPSAobWVhbihub25fZWNpZ19jdXJyZW50LCBuYS5ybSA9IFRSVUUpKjEwMCkpICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAteWVhciwgbmFtZXNfdG8gPSAiQ2F0ZWdvcnkiLCB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpICU+JQogICAgc2VwYXJhdGUoQ2F0ZWdvcnksIGludG8gPSBjKCJQcm9kdWN0IiwgIlVzZXIiKSwgc2VwID0gIl8iKSAlPiUKICAgIGdncGxvdChhZXMoeD15ZWFyLCB5PWBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCwgY29sb3I9UHJvZHVjdCkpICsKICAgIGdlb21fbGluZShsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFLCBzaXplID0gMikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB2X2NvbG9ycykgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA2MCwgYnkgPSAxMCksIGxpbWl0cyA9IGMoMCw2MCkpICsKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSAiSG93IGRvZXMgdGhlIHJhdGUgb2YgY3VycmVudGx5IHVzaW5nIGUtY2lnYXJldHRlcyBcbmNvbXBhcmUgdG8gY3VycmVudGx5IHVzaW5nIG90aGVyIHByb2R1Y3RzIG92ZXIgdGltZT8iLAogICAgICAgICB5ID0gIiUgb2Ygc3R1ZGVudHMiKQoKcGxvdDgKYGBgCgojIyMgUHV0dGluZyBwbG90cyB0b2dldGhlcgoKTm93IHdlIHdpbGwgcHV0IHRoZXNlIHBsb3RzIHRvZ2V0aGVyIHVzaW5nIHRoZSBgcGxvdF9ncmlkKClgIGZ1bmN0aW9uIG9mIHRoZSBgY293cGxvdGAgcGFja2FnZS4gIFdlIHdpbGwgYWxzbyBtb2RpZnkgdGhlIGxhYmVscyB1c2luZyB0aGUgYGdnZHJhdygpYCBmdW5jdGlvbiwgd2hpY2ggaXMgYWxzbyBwYXJ0IG9mIHRoZSBgY293cGxvdGAgcGFja2FnZS4KCmBgYHtyLCBmaWcuaGVpZ2h0PTEwfQpwbG90QV91dyA8LSBwbG90MSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgbGFicyh0aXRsZSA9ICJUb2JhY2NvIHByb2R1Y3QgdXNlcnMgbW9yZSBwcmV2YWxlbnQgYWZ0ZXIgMjAxNyIsCiAgICAgICAgIHN1YnRpdGxlID0gTlVMTCwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnBsb3RCX3V3IDwtIHBsb3Q3ICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICBsYWJzKHRpdGxlID0gIiUgRXZlciB0cnlpbmcgZS1jaWdhcmV0dGVzIGluY3JlYXNlcyAmXG4lIEV2ZXIgdHJ5aW5nIG90aGVyIHByb2R1Y3RzIGRlY3JlYXNlcyIsCiAgICAgICAgIHN1YnRpdGxlID0gTlVMTCwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnBsb3RDX3V3IDwtIHBsb3Q4ICsgCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgbGFicyh0aXRsZSA9ICIlIEN1cnJlbnRseSB1c2luZyBlLWNpZ2FyZXR0ZXMgaW5jcmVhc2VzICZcbiUgQ3VycmVudGx5IHVzaW5nIG90aGVyIHByb2R1Y3RzIGRlY3JlYXNlcyIsCiAgICAgICAgIHN1YnRpdGxlID0gTlVMTCwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnRpdGxlX3V3IDwtIGdnZHJhdygpICsgCiAgZHJhd19sYWJlbCgKICAgICJIYXZlIGUtY2lnYXJldHRlIHJhdGVzIHBvc3NpYmx5IGluZmx1ZW5jZWQgdG9iYWNjbyB1c2U/IiwKICAgIGZvbnRmYWNlID0gJ2JvbGQnLAogICAgc2l6ZT0xNCwKICAgIHggPSAwLAogICAgaGp1c3QgPSAwCiAgKSArCiAgdGhlbWUoCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigwLCAwLCAwLCAwKQogICkKCnBsb3RzQV91dyA8LSBwbG90X2dyaWQocGxvdEFfdXcsCiAgICAgICAgICAgICAgICAgICAgIHJlbF93aWR0aHMgPSBjKDEsMSkpCnBsb3RzQkNfdXcgPC0gcGxvdF9ncmlkKHBsb3RCX3V3LAogICAgICAgICAgICAgICAgICAgICAgICBwbG90Q191dywKICAgICAgICAgICAgICAgICAgICAgICAgcmVsX3dpZHRocyA9IGMoMSwxKSkKCiMgdGhpcyB3aWxsIHRha2UgdGhlIGxlZ2VuZCBmcm9tIHBsb3QxYyB0byB1c2UgYXMgdGhlIGxlZ2VuZCBmb3IgdGhlIHBsb3Qgd2UgYXJlIGNyZWF0aW5nCmxlZ2VuZF91dyA8LSBnZXRfbGVnZW5kKHBsb3QxYyArCiAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikpCgpmaWd1cmVfdXcgPC0gcGxvdF9ncmlkKHRpdGxlX3V3LAogICAgICAgICAgICAgICAgICAgICAgIHBsb3RzQV91dywKICAgICAgICAgICAgICAgICAgICAgICBwbG90c0JDX3V3LAogICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF91dywKICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMSwKICAgICAgICAgICAgICAgICAgICAgICByZWxfaGVpZ2h0cyA9IGMoMC4xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjEpLAogICAgICAgICAgICAgICAgICAgICAgIHNjYWxlID0gMS4wKQoKZmlndXJlX3V3CmBgYAoKCiMjIyBTdXJ2ZXkgV2VpZ2h0aW5nCgpJdCB0dXJucyBvdXQgdGhhdCBvdXIgYW5hbHlzaXMgdGh1cyBmYXIgaGFzIGJlZW4gYnJ1c2hpbmcgYW4gaW1wb3J0YW50IHN0YXRpc3RpY2FsIGNvbmNlcHQgdW5kZXIgdGhlIHJ1ZywgcmVsYXRlZCB0byBob3cgb3VyIGRhdGEgd2VyZSBjb2xsZWN0ZWQuIE91ciBkYXRhIGNvbWUgZnJvbSByZXNwb25zZXMgdG8gYSBzdXJ2ZXksIHdoaWNoIG1heSBoYXZlIGEgcGFydGljdWxhciBzYW1wbGluZyBzY2hlbWUgdG8gY2FwdHVyZSBkYXRhIGFib3V0IHRoZSBwb3B1bGF0aW9uIHdlIGFyZSBpbnRlcmVzdGVkIGluLiBGb3IgZXhhbXBsZSwgdGhlIHN1cnZleSBtYXkgYmUgZGVzaWduZWQgdG8gY2FwdHVyZSBhIHNldCBvZiBpbmRpdmlkdWFscyB3aG8gcmVmbGVjdCB0aGUgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBwb3B1bGF0aW9uIHRoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gZHJhd2luZyBjb25jbHVzaW9ucyBhYm91dC4gSG93ZXZlciwgb25seSBhIGZyYWN0aW9uIG9mIHRoZSBpbmRpdmlkdWFscyB3aG8gd2VyZSBjb250YWN0ZWQgYWJvdXQgdGFraW5nIHRoZSBzdXJ2ZXkgbWF5IGhhdmUgY29tcGxldGVkIGl0LCBhbmQgdGhpcyBmcmFjdGlvbiBvZiBpbmRpdmlkdWFscyBtYXkgbm8gbG9uZ2VyIGJlIHJlcHJlc2VudGF0aXZlIG9mIHRoZSBwb3B1bGF0aW9uLiBPciB0aGUgc3VydmV5IG1heSBiZSBkZXNpZ25lZCB0byBvdmVyLXNhbXBsZSBhIHBhcnRpY3VsYXIgZ3JvdXAgb2YgaW50ZXJlc3Qgc28gdGhhdCBpbmRpdmlkdWFscyBmcm9tIHRoYXQgZ3JvdXAgc2hvdyB1cCBtb3JlIG9mdGVuIGFzIHN1cnZleSByZXNwb25kZW50cyB0aGFuIGFyZSBwcmVzZW50IGluIHRoZSBwb3B1bGF0aW9uIG92ZXJhbGwuIEluIG9yZGVyIHRvIGFjY291bnQgZm9yIHRoZSBmYWN0IHRoYXQgdGhlIHN1cnZleSByZXNwb25kZW50cyBtYXkgbm90IHJlZmxlY3QgdGhlIGNvbXBvc2l0aW9uIG9mIHRoZSBwb3B1bGF0aW9uIHdlIHdhbnQgdG8gZ2VuZXJhbGl6ZSB0bywgd2UgY2FuIGVtcGx5IGEgdGVjaG5pcXVlIGNhbGxlZCBbc3VydmV5IHdlaWdodGluZ10oaHR0cDovL3d3dy5hcHBsaWVkLXN1cnZleS1tZXRob2RzLmNvbS93ZWlnaHQuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifS4KClN1cnZleSB3ZWlnaHRpbmcgaXMgYSBjb21tb24gdGVjaG5pcXVlIHVzZWQgaW4gc3VydmV5IGRhdGEgYW5hbHlzaXMgYmVjYXVzZSBvZnRlbiB0aGUgaW5kaXZpZHVhbHMgdGhhdCB0YWtlIGEgc3VydmV5IGFyZSBub3QgbmVjZXNzYXJpbHkgcmVwcmVzZW50YXRpdmUgb2YgdGhlIHBvcHVsYXRpb24gdGhhdCB3ZSBhcmUgdHJ5aW5nIHRvIGdhdGhlciBpbmZvcm1hdGlvbiBhYm91dC4gRm9yIGV4YW1wbGUsIHdlIG1heSBoYXZlIG1vcmUgZmVtYWxlcyB0aGF0IHJlc3BvbmQgdG8gdGhlIHN1cnZleSB0aGFuIG1hbGVzIGJlY2F1c2UgcGVyaGFwcyBmZW1hbGUgc3R1ZGVudHMgd2VyZSBtb3JlIHdpbGxpbmcgdG8gcGFydGljaXBhdGUuIEluIHRoaXMgY2FzZSwgdGhlIHByb3BvcnRpb24gb2YgZGF0YSB2YWx1ZXMgaW4gb3VyIGRhdGEgd2lsbCBiZSBzbWFsbGVyIGZvciB0aGUgbWFsZXMgdGhhbiB0aGUgcHJvcG9ydGlvbiBvZiBhY3R1YWwgbWFsZSBzdHVkZW50cyBhbmQgbGFyZ2VyIGZvciB0aGUgZmVtYWxlcyB0aGFuIHRoZSB0cnVlIHByb3BvcnRpb24gb2YgYWN0dWFsIGZlbWFsZSBzdHVkZW50cy4gVG8gZ2V0IGEgYmV0dGVyIGVzdGltYXRlIG9mIG92ZXJhbGwgZS1jaWdhcmV0dGUgc21va2luZyByYXRlcywgdGhlIGRhdGEgZnJvbSB0aGUgbWFsZXMgY2FuIGJlIHdlaWdodGVkIGJhc2VkIG9uIHRoZSB0cnVlIHByb3BvcnRpb24gb2YgbWFsZSBzdHVkZW50cyB0byBhbXBsaWZ5IHRoZSBjb250cmlidXRpb24gb2YgdGhlIHJlc3BvbnNlcyBmcm9tIHRoZSBtYWxlcyB0aGF0IGRpZCBwYXJ0aWNpcGF0ZS4gQ29udmVyc2VseSwgdGhlIGZlbWFsZSBkYXRhIGNhbiBiZSB3ZWlnaHRlZCB0byBkaW1pbmlzaCB0aGUgY29udHJpYnV0aW9uIGlmIHRoZWlyIHJlc3BvbnNlcyB0byB0aGUgb3ZlcmFsbCBwaWN0dXJlLiBXZSB3aWxsIHNlZSBpZiB1c2luZyBzdXJ2ZXkgd2VpZ2h0aW5nIGNoYW5nZXMgdGhlIGdlbmVyYWwgdHJlbmRzIHRoYXQgd2Ugc2VlIGluIG91ciBkYXRhLiAKCkNhbGN1bGF0aW5nIHN1cnZleSB3ZWlnaHRzIGludm9sdmVzIG1ha2luZyBhIHdlaWdodCBiYXNlZCBvbiB0aGUgcmF0aW8gb2YgdGhlIHByb3BvcnRpb24gb2Ygc3VydmV5IHJlc3BvbmRlbnRzIGZyb20gYSBwYXJ0aWN1bGFyIGdyb3VwIGFuZCB0aGUgYWN0dWFsIHByb3BvcnRpb24gb2YgdGhhdCBncm91cCBpbiB0aGUgcG9wdWxhdGlvbi4gRm9yIGV4YW1wbGUsIGxldCdzIHNheSB0aGF0IGZlbWFsZXMgYWNjb3VudCBmb3IgNTAlIG9mIHRoZSBwb3B1bGF0aW9uIGFuZCBtYWxlcyBhY2NvdW50IGZvciA1MCAlIG9mIHRoZSBwb3B1bGF0aW9uLiBMZXQncyBhbHNvIHNheSB0aGF0IDc1JSBvZiB0aGUgcmVzcG9uZGVudHMgdG8gdGhlIHN1cnZleSB3ZXJlIGZlbWFsZSBhbmQgb25seSAyNSUgd2VyZSBtYWxlcy4gCgpUaGVuIHdlIGNvdWxkIGNhbGN1bGF0ZSBzdXJ2ZXkgd2VpZ2h0cyB1c2luZyB0aGlzIGZvcm11bGE6CgokJCBcZnJhY3tcdGV4dHthY3R1YWwgcHJvcG9ydGlvbiBvZiBncm91cCBpbiB0aGUgcG9wdWxhdGlvbn19e1x0ZXh0eyBwcm9wb3J0aW9uIG9mIGdyb3VwIGluIHRoZSByZXNwb25kZW50c319JCQgIAoKVGh1cyB0aGUgd2VpZ2h0IGZvciB0aGUgZmVtYWxlcyB3b3VsZCBiZSBjYWxjdWxhdGVkIGFzOgoKJCQgXGZyYWN7LjV9ey43NX0gPSAuNjckJCAgCgpUaGUgd2VpZ2h0IGZvciB0aGUgbWFsZXMgd291bGQgYmUgY2FsY3VsYXRlZCBhczoKCiQkIFxmcmFjey41fXsuMjV9ID0gMiQkCgpUaGVyZWZvcmUgZWFjaCBtYWxlIHJlc3BvbnNlIHZhbHVlIHdvdWxkIGJlIG11bHRpcGxpZWQgYnkgYSBmYWN0b3Igb2YgMiBhbmQgd291bGQgaGF2ZSB0d2ljZSB0aGUgY29udHJpYnV0aW9uLCB3aGlsZSB0aGUgZmVtYWxlIHJlc3BvbnNlIHZhbHVlcyB3b3VsZCBoYXZlIG9ubHkgYWJvdXQgNzAlIG9mIHRoZSBjb250cmlidXRpb24gdGhhdCB0aGV5IHdvdWxkIGhhdmUgaGFkIHdpdGhvdXQgd2VpZ2h0aW5nLgoKTm90ZSB0aGF0IHN1cnZleSB3ZWlnaHRzIGFyZSBpbiByZWFsaXR5IGNvcnJlY3RlZCBmb3Igb3RoZXIgYXNwZWN0cyAtIGZvciBleGFtcGxlIHRoZSByZXNwb25zZSByYXRlIHRvIGluZGl2aWR1YWwgcXVlc3Rpb25zLgoKV2UgZG8gbm90IG5lZWQgdG8gY2FsY3VsYXRlIHN1cnZleSB3ZWlnaHRzIGZvciBvdXIgZGF0YSBhcyB0aGV5IHdlcmUgYWxyZWFkeSBzdXBwbGllZCBpbiB0aGUgZGF0YSBzZXQsIGFzIGRlc2NyaWJlZCBpbiB0aGUgY29kZWJvb2tzLiAKCiMjIyMgYHNydnlyYCBwYWNrYWdlIGFuZCBzdXJ2ZXkgZGVzaWduIAoKKioqCgpXZSB3aWxsIG5vdyB1c2UgdGhlIGBzcnZ5cmAgcGFja2FnZSB0byBldmFsdWF0ZSBvdXIgZGF0YSB1c2luZyBzdXJ2ZXkgd2VpZ2h0cyB0aGF0IHdlcmUgcHJvdmlkZWQgaW4gdGhlIGRhdGEgZm9yIGVhY2ggeWVhciwgYXMgZGVzY3JpYmVkIGluIHRoZSByZXNwZWN0aXZlIGNvZGVib29rcy4gVGhpcyBwYWNrYWdlIGNvbnRhaW5zIGZ1bmN0aW9ucyB0aGF0IGFsbG93IHRoZSB1c2VyIHRvIGVhc2lseSBwZXJmb3JtIGNhbGN1bGF0aW9ucyBmcm9tIHRoZSBkYXRhIHRoYXQgdGFrZSB0aGUgc3VydmV5IGRlc2lnbiBpbnRvIGFjY291bnQsIHdpdGhvdXQgaGF2aW5nIHRvIHdvcmsgb3V0IHRoZSBtYXRoIGJ5IGhhbmQuCgpXaXRoaW4gdGhlIGRhdGEgeW91IHdpbGwgc2VlIHRoYXQgd2UgaGF2ZSB0aHJlZSB2YXJpYWJsZXMgcmVsYXRlZCB0byB0aGUgc3VydmV5IHNhbXBsaW5nIHNjaGVtZTogIGBwc3VgLCBgZmlud2d0YCwgYW5kIGBzdHJhdHVtYC4gRGV0YWlscyBhYm91dCB0aGVzZSB2YXJpYWJsZXMgYXJlIGF2YWlsYWJsZSwgZm9yIGV4YW1wbGUsIGluIHRoZSBbMjAxOSBNZXRob2RvbG9neSBSZXBvcnRdKC4vZG9jcy8yMDE5LW55dHMtZGF0YXNldC1hbmQtY29kZWJvb2stbWljcm9zb2Z0LWV4Y2VsLzIwMTktbnl0cy1tZXRob2RvbG9neS1yZXBvcnQtcC5wZGYpe3RhcmdldD0iX2JsYW5rIn0uCgpJbiBicmllZiB0aGV5IHJlcHJlc2VudDogCgoxKSBgcHN1YDogU3VydmV5cyBsaWtlIHRoZSBvbmUgdXNlZCB0byBjcmVhdGUgdGhlIGRhdGEgd2UgYXJlIHVzaW5nIG9mdGVuIHNhbXBsZSBwZW9wbGUgYmFzZWQgb24gc3RyYXRhLiBUaGlzIGlzIGRvbmUgdG8gZW5zdXJlIHRoYXQgdGhlIHJlc3BvbnNlcyBhcmUgcmVwcmVzZW50YXRpdmUgb2YgdGhlIHBvcHVsYXRpb24gb2YgaW50ZXJlc3QuIFRodXMsIG9mdGVuIHBlb3BsZSBmaXJzdCB0aGluayBhYm91dCBlbnN1cmluZyB0aGF0IHN1cnZleXMgYXJlIGNvbmR1Y3RlZCBpbiBhIHZhcmlldHkgb2YgZ2VvZ3JhcGhpY2FsIGFyZWFzLiBUaGlzIGlzIG9mdGVuIGNhbGxlZCB0aGUgKipwcmltYXJ5IHNhbXBsaW5nIHVuaXQqKiBvciAqKlBTVSoqLiBJbiBbdGhpcyBzdXJ2ZXldKGh0dHBzOi8vd2ViLnNwaC5oYXJ2YXJkLmVkdS9tY2gtZGF0YS1jb25uZWN0L3Jlc3VsdHMvbmF0aW9uYWwteW91dGgtdG9iYWNjby1zdXJ2ZXktbnl0cy8pe3RhcmdldD0iX2JsYW5rIn0sIHRoZSBjb3VudHkgd2hlcmUgdGhlIHN0dWRlbnQncyBzY2hvb2wgd2FzIGxvY2F0ZWQgd2FzIHVzZWQgYXMgdGhlIFBTVS4gCgoyKSBgc3RyYXR1bWA6IEEgY2F0ZWdvcmljYWwgdmFyaWFibGUgdGhhdCBpbmRpY2F0ZXMgc3Vic2V0cyBvZiB0aGUgZGF0YSB0aGF0IGluY2x1ZGUgcmVzcG9uZGVudHMgZnJvbSBkaWZmZXJlbnQgKlBTVXMqLiBJbiBvdXIgY2FzZSwgc3RyYXRhIGFyZSBkZXRlcm1pbmVkIGJ5IHRoZSBwcmVkb21pbmFudCBtaW5vcml0eSBpbiB0aGUgUFNVIChOb24tSGlzcGFuaWMgQmxhY2sgb3IgSGlzcGFuaWMpLCB3aGV0aGVyIHRoZSBQU1UgaXMgdXJiYW4gb3Igbm9uLXVyYmFuLCBhbmQgd2hhdCBwZXJjZW50IG9mIHRoZSBzdHVkZW50cyBpbiB0aGUgUFNVIGZhbGwgaW50byB0aGUgcHJlZG9taW5hbnQgbWlub3JpdHkgZ3JvdXAuIFBTVXMgYXJlIGFsbG9jYXRlZCBhY3Jvc3MgdGhlIDE2IHBvc3NpYmxlIHN0cmF0YSBhY2NvcmRpbmcgdG8gdGhlIHNhbXBsaW5nIHNjaGVtZS4gVGhlc2Ugc3RyYXRhIHZhbHVlcyBhbGxvdyBlc3RpbWF0ZXMgYmFzZWQgb24gdGhlIHN1cnZleSByZXNwb25zZXMgdG8gYmUgY2FsY3VsYXRlZCB1c2luZyBkaWZmZXJlbnQgc3RyYXRhIGFsbG93aW5nIGZvciBpbXByb3ZlZCBwcmVjaXNpb24gb2YgdGhlIHJlc3BvbnNlIGVzdGltYXRlcy4KCkFWT0NBRE86IEkgYWRkZWQgYSBidW5jaCBvZiBkZXRhaWxzIGhlcmUgdG8gdGhlIGRlZmluaXRpb24gb2Ygc3RyYXR1bSAtIHBlcmhhcHMgZ2l2ZSBpdCBhIHF1aWNrIHJlYWQuIEkgYWxzbyB0aGluayBpdCBtaWdodCBiZSB3b3J0aCBpbmNsdWRpbmcgb25lIG9mIHRoZSBNZXRob2RvbG9neSBSZXBvcnRzLCB3aGljaCBpcyB3aGVyZSBJIHB1bGxlZCB0aGlzIGluZm9ybWF0aW9uIGZyb20uCgozKSBgZmlud2d0YDogVGhlIHN1cnZleSB3ZWlnaHQgd2hpY2ggd2FzIGNhbGN1bGF0ZWQgYmFzZWQgb24gYSB2YXJpZXR5IG9mIGZhY3RvcnMuCgpUaGlzIFtsaW5rXShodHRwczovL3dlYi5zcGguaGFydmFyZC5lZHUvbWNoLWRhdGEtY29ubmVjdC9yZXN1bHRzL25hdGlvbmFsLXlvdXRoLXRvYmFjY28tc3VydmV5LW55dHMvKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCB0aGlzIFtsaW5rXShodHRwczovL29zZi5pby9uN3IzMil7dGFyZ2V0PSJfYmxhbmsifSBoYXZlIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHN0dWR5IGRlc2lnbiBvZiB0aGUgZGF0YSB0aGF0IHdlIGFyZSB1c2luZy4KCkZvciBkZXRhaWxlZCBpbmZvcm1hdGlvbiBvbiBzdWNoIHN1cnZleSBkZXNpZ25zIGluIGdlbmVyYWwgc2VlIFtoZXJlXShodHRwOi8vd3d3LmFzYXNybXMub3JnL1Byb2NlZWRpbmdzL3kyMDA4L0ZpbGVzLzMwMTgzNS5wZGYpe3RhcmdldD0iX2JsYW5rIn0gYW5kIFtoZXJlXShodHRwOi8vb2N3Lmpoc3BoLmVkdS9jb3Vyc2VzL1N0YXRNZXRob2RzRm9yU2FtcGxlU3VydmV5cy9QREZzL0xlY3R1cmU1LnBkZil7dGFyZ2V0PSJfYmxhbmsifS4KCldlIHdpbGwgdXNlIHRoZSBgYXNfc3VydmV5X2Rlc2lnbigpYCBmdW5jdGlvbiBvZiB0aGUgYHNydnlyYHBhY2thZ2UgdG8gY3JlYXRlIGEgc3VydmV5IG9iamVjdCB3aXRoIGEgc3BlY2lmaWVkIHN1cnZleSBkZXNpZ24uIFRoaXMgaXMgYSBzcGVjaWFsIFIgb2JqZWN0IHRoYXQgaW5jbHVkZXMgaW5mb3JtYXRpb24gYWJvdXQgaG93IHRoZSBzdXJ2ZXkgd2FzIGNvbmR1Y3RlZCB0aGF0IGNhbiBiZSB0YWtlbiBpbnRvIGFjY291bnQgaW4gdGhlIGFuYWx5c2lzLgoKVGhlcmUgYXJlIHNldmVyYWwgYXJndW1lbnRzIHRvIHBheSBhdHRlbnRpb24gdG86CgoxKSBUaGUgYHN0cmF0YWAgYXJndW1lbnQgaXMgdXNlZCB0byBzcGVjaWZ5IHRoZSB2YXJpYWJsZShzKSB0aGF0IGRlZmluZWQgc3RyYXRhIGluIHRoZSBkYXRhLiBJbiB0aGlzIGNhc2UsIHdlIHdpbGwgdXNlIHRoZSBgc3RyYXR1bWAgdmFyaWFibGUuCjIpIFRoZSBgaWRzYCBhcmd1bWVudCBpcyB1c2VkIHRvIGRlZmluZSBjbHVzdGVyIGlkcyB3aXRoaW4gdGhlIGRhdGEuIEluIHRoaXMgY2FzZSB3ZSB3aWxsIHVzZSB0aGUgYHBzdWAgdmFyaWFibGUuCjMpIFRoZSBgd2VpZ2h0YCBhcmd1bWVudCBpcyB0aGUgIHVzZWQgdG8gZGVmaW5lIHdoaWNoIHZhcmlhYmxlKHMpIGFyZSB0aGUgc3VydmV5IHdlaWdodHMuCjQpIFRoZSBgbmVzdCA9IFRSVUVgIGFyZ3VtZW50LCBmb3JjZXMgY2x1c3RlciBpZHMgKGluIHRoaXMgY2FzZSB0aGUgUFNVKSB0byBiZSBuZXN0ZWQgd2l0aGluIHRoZSBzdHJhdGEuCgpXZSBjYW4gdGhlbiB1c2UgdGhlIGBzdXJ2ZXlfbWVhbigpYCBmdW5jdGlvbiB0byBjYWxjdWxhdGUgcGVyY2VudGFnZXMgb2Ygc3R1ZGVudHMgd2hvIHJlcG9ydCB1c2luZyB0b2JhY2NvIGZvciBlYWNoIHllYXIgd2hpbGUgYWNjb3VudGluZyBmb3IgdGhlIHN1cnZleSBkZXNpZ24gYW5kIHdlaWdodHMuIFdlIHdpbGwgc3BlY2lmeSB0aGF0IHdlIHdhbnQgW2NvbmZpZGVuY2UgaW50ZXJ2YWxdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0NvbmZpZGVuY2VfaW50ZXJ2YWwpIGVzdGltYXRlcyBieSB1c2luZyB0aGUgYHZhcnR5cGUgPSAiY2kiYCBhcmd1bWVudC4gVGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGluIG91ciBjYXNlIGdpdmUgYSByYW5nZSBvZiBwb3NzaWJsZSB2YWx1ZXMgZm9yIHRoZSB0cnVlIHBvcHVsYXRpb24gbWVhbiBiYXNlZCBvbiB0aGUgZGF0YSBvYnNlcnZlZCBpbiB0aGUgc3VydmV5LiBXZSB3aWxsIG11bHRpcGx5IHRoZXNlIHZhbHVlcyBieSAxMDAgdG8gZ2V0IHBlcmNlbnRhZ2VzLiAoTm90ZTogV2UgY291bGQgYWxzbyBoYXZlIGNhbGN1bGF0ZWQgY29uZmlkZW5jZSBpbnRlcnZhbHMgZm9yIHRoZSB1bndlaWdodGVkIHJlc3VsdHMgYWJvdmUgYnkgY29tcHV0aW5nIHRoZW0gYnkgaGFuZDsgd2UgbGVhdmUgdGhpcyBhcyBhIHBvdGVudGlhbCBleGVyY2lzZS4pCgpTaW5jZSB0aGUgc3VydmV5IHdlaWdodHMgYXJlIHNwZWNpZmljIHRvIGEgc2luZ2xlIHllYXIgb2YgdGhlIHN1cnZleSByZXN1bHRzLCB3ZSBuZWVkIHRvIGNyZWF0ZSBzdXJ2ZXkgZGVzaWduIG9iamVjdHMgZm9yIGVhY2ggeWVhciBzZXBhcmF0ZWx5LiBXZSB3aWxsIHVzZSBgZ3JvdXBfYnlgIGFuZCBgZ3JvdXBfbW9kaWZ5YCwgd2hpY2ggaXMgYWxzbyBmcm9tIHRoZSBgZHBseXJgIHBhY2thZ2UsIHRvIGRvIHRoaXMuIFdlIGZpcnN0IHdyaXRlIHRoZSBmdW5jdGlvbiB0aGF0IHdlIHdhbnQgdG8gY2FsbCBvbiBlYWNoIGdyb3VwLgoKVGhpcyBmdW5jdGlvbiB3aWxsIHRha2UgYW4gaW5wdXQgY2FsbGVkIGBjdXJyWWVhcmAsIHdoaWNoIHdpbGwgYmUgb25lIHNldCBvZiBzdXJ2ZXkgcmVzcG9uc2VzIGZvciBhIHNwZWNpZmljIHllYXIsIGFuZCB0aGVuIGNyYWV0ZXMgYSBzdXJ2ZXkgZGVzaWduIGJhc2VkIG9uIHRoZSBgc3RyYXR1bWAgYW5kIGBmaW53Z3RgIHNwZWNpZmljIHRvIHRoYXQgeWVhci4gSXQgd2lsbCB0aGVuIGNhbGN1bGF0ZSB0aGUgbWVhbiBmb3Igc3R1ZGVudCByZXNwb25kYW50cyB3aG8gaGF2ZSBldmVyIHRyaWVkIGFueSB0b2JhY2NvIHByb2R1Y3RzIG9yIGFyZSBhIGN1cnJlbnQgdXNlciBvZiBhbnkgdG9iYWNjbyBwcm9kdWN0cyBhY2NvdW50aW5nIGZvciB0aGUgc3VydmV5IGRlc2lnbiBhbmQgd2VpZ2h0cyB1c2luZyBgc3VydmV5X21lYW4oKWAgYXMgd2FzIGp1c3QgZGVzY3JpYmVkLiBUaGUgZnVuY3Rpb24gd2lsbCB0aGVuIHdyYW5nbGUgdGhlIGRhdGEgdG8gcHJvZHVjZSBuZXcgdmFyaWFibGVzIGFib3V0IHRoZSB0eXBlIG9mIG1lYW4gZXN0aW1hdGUgdGhhdCB3YXMgZ2l2ZW4gZnJvbSB0aGUgYHN1cnZleV9tZWFuYCBvdXRwdXQgYW5kIHRoZSB0eXBlIG9mIHVzZXIuIFRoaXMgCgojIyMgV2VpZ2h0ZWQgU2FtcGxlCmBgYHtyfQpzdXJ2ZXlNZWFuQSA8LSBmdW5jdGlvbihjdXJyWWVhcil7CiAgb3B0aW9ucyhzdXJ2ZXkubG9uZWx5LnBzdSA9ICJhdmVyYWdlIikKICBjdXJyWWVhciAlPiUKICBhc19zdXJ2ZXlfZGVzaWduKHN0cmF0YSA9IHN0cmF0dW0sIAogICAgICAgICAgICAgICAgICAgICAgaWRzID0gcHN1LCAKICAgICAgICAgICAgICAgICAgd2VpZ2h0ICA9IGZpbndndCwgCiAgICAgICAgICAgICAgICAgICAgIG5lc3QgPSBUUlVFKSAlPiUKICAgc3VtbWFyaXplKHRvYmFjY29fZXZlciA9IHN1cnZleV9tZWFuKHRvYmFjY29fZXZlciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXJ0eXBlID0gImNpIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgdG9iYWNjb19jdXJyZW50ID0gc3VydmV5X21lYW4odG9iYWNjb19jdXJyZW50LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcnR5cGUgPSAiY2kiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkpIH0KCgpueXRzX2RhdGEgJT4lIAogIGdyb3VwX2J5KHllYXIpICU+JQogIGdyb3VwX21vZGlmeSh+c3VydmV5TWVhbkEoLngpKSAlPiUKICBoZWFkKCkKCgoKYGBgCgpOb3cgbGV0J3MgbWFrZSB0aGUgZnVuY3Rpb24gd3JhbmdsZSB0aGUgb3V0cHV0IGluIGEgbW9yZSB1c2FibGUgZm9ybSB0b286CmBgYHtyfQoKc3VydmV5TWVhbkEgPC0gZnVuY3Rpb24oY3VyclllYXIpewogIG9wdGlvbnMoc3VydmV5LmxvbmVseS5wc3UgPSAiYXZlcmFnZSIpCiAgY3VyclllYXIgJT4lCiAgYXNfc3VydmV5X2Rlc2lnbihzdHJhdGEgPSBzdHJhdHVtLCAKICAgICAgICAgICAgICAgICAgICAgIGlkcyA9IHBzdSwgCiAgICAgICAgICAgICAgICAgIHdlaWdodCAgPSBmaW53Z3QsIAogICAgICAgICAgICAgICAgICAgICBuZXN0ID0gVFJVRSkgJT4lCiAgIHN1bW1hcml6ZSh0b2JhY2NvX2V2ZXIgPSBzdXJ2ZXlfbWVhbih0b2JhY2NvX2V2ZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFydHlwZSA9ICJjaSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSwKICAgICAgICAgIHRvYmFjY29fY3VycmVudCA9IHN1cnZleV9tZWFuKHRvYmFjY29fY3VycmVudCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXJ0eXBlID0gImNpIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpKSAgJT4lCiAgbXV0YXRlX2FsbCggIioiLCAxMDApICU+JQogICAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgCiAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiVHlwZSIsIAogICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgbXV0YXRlKEVzdGltYXRlID0gY2FzZV93aGVuKHN0cl9kZXRlY3QoVHlwZSwiX2xvdyIpIH4gIkxvd2VyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIl91cHAiLCBUeXBlKSB+ICJVcHBlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJNZWFuIiksCiAgICAgICAgIFVzZXIgPSBjYXNlX3doZW4oZ3JlcGwoImV2ZXIiLCBUeXBlKSB+ICJFdmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiY3VycmVudCIsIFR5cGUpIH4gIkN1cnJlbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTWVhbiIpKQogIAp9CgpueXRzX2RhdGEgJT4lIAogIGdyb3VwX2J5KHllYXIpICU+JQogIGdyb3VwX21vZGlmeSh+c3VydmV5TWVhbkEoLngpKQoKYGBgCgpgYGB7cn0KIyMjIEFWT0NBRE86IFJlbW92ZSByZXN0IG9mIGNodW5rIGZyb20gaGVyZSBpZiB5b3UgYXJlIE9LIHdpdGggdGhpcyB3YXkgb2YgZG9pbmcgaXQKbnl0c19kYXRhICU+JQogIGFzX3N1cnZleV9kZXNpZ24oc3RyYXRhID0gc3RyYXR1bSwgCiAgICAgICAgICAgICAgICAgICAgICBpZHMgPSBwc3UsIAogICAgICAgICAgICAgICAgICB3ZWlnaHQgID0gZmlud2d0LCAKICAgICAgICAgICAgICAgICAgICAgbmVzdCA9IFRSVUUpICU+JQogICAgICAgICAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgIHN1bW1hcml6ZSh0b2JhY2NvX2V2ZXIgPSBzdXJ2ZXlfbWVhbih0b2JhY2NvX2V2ZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFydHlwZSA9ICJjaSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSwKICAgICAgICAgIHRvYmFjY29fY3VycmVudCA9IHN1cnZleV9tZWFuKHRvYmFjY29fY3VycmVudCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXJ0eXBlID0gImNpIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpKSAgJT4lCiAgbXV0YXRlX2F0KHZhcnMoLXllYXIpLCAiKiIsIDEwMCkgJT4lCiAgICBwaXZvdF9sb25nZXIoY29scyA9IC15ZWFyLCAKICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJUeXBlIiwgCiAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiKSAlPiUKICBtdXRhdGUoRXN0aW1hdGUgPSBjYXNlX3doZW4oZ3JlcGwoIl9sb3ciLCBUeXBlKSB+ICJMb3dlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJfdXBwIiwgVHlwZSkgfiAiVXBwZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTWVhbiIpLAogICAgICAgICBVc2VyID0gY2FzZV93aGVuKGdyZXBsKCJldmVyIiwgVHlwZSkgfiAiRXZlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoImN1cnJlbnQiLCBUeXBlKSB+ICJDdXJyZW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk1lYW4iKSkgJT4lCiAgaGVhZCgpCgoKYGBgCgpXZSB3aWxsIG5vdyBtYWtlIGEgcGxvdCB1c2luZyB0aGlzIGRhdGEuIFRoZSBjb25maWRlbmNlIGludGVydmFscyBhcmUgaW5jbHVkZWQgdXNpbmcgdGhlIGBnZW9tX2xpbmVyYW5nZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UuCgpgYGB7cn0KIyMjIEFWT0NBRE86IFJlbW92ZSB0aGlzIGZpcnN0IHZlcnNpb24gb2YgdGhlIGZpZ3VyZSBpZiB5b3UgYXJlIE9LIHdpdGggbXkgbW9kaWZpY2F0aW9ucyBiZWxvdwpwbG90QV93IDwtIG55dHNfZGF0YSAlPiUKICBhc19zdXJ2ZXlfZGVzaWduKHN0cmF0YSA9IHN0cmF0dW0sIAogICAgICAgICAgICAgICAgICAgICAgaWRzID0gcHN1LCAKICAgICAgICAgICAgICAgICAgd2VpZ2h0ICA9IGZpbndndCwgCiAgICAgICAgICAgICAgICAgICAgIG5lc3QgPSBUUlVFKSAlPiUKICAgICAgICAgIGdyb3VwX2J5KHllYXIpICU+JQogICBzdW1tYXJpemUodG9iYWNjb19ldmVyID0gc3VydmV5X21lYW4odG9iYWNjb19ldmVyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcnR5cGUgPSAiY2kiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSksCiAgICAgICAgICB0b2JhY2NvX2N1cnJlbnQgPSBzdXJ2ZXlfbWVhbih0b2JhY2NvX2N1cnJlbnQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFydHlwZSA9ICJjaSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSkgICU+JQogIG11dGF0ZV9hdCh2YXJzKC15ZWFyKSwgIioiLCAxMDApICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAteWVhciwgCiAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiVHlwZSIsIAogICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgbXV0YXRlKEVzdGltYXRlID0gY2FzZV93aGVuKGdyZXBsKCJfbG93IiwgVHlwZSkgfiAiTG93ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiX3VwcCIsIFR5cGUpIH4gIlVwcGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJNZWFuIiksCiAgICAgICAgIFVzZXIgPSBjYXNlX3doZW4oZ3JlcGwoImV2ZXIiLCBUeXBlKSB+ICJFdmVyIiwKICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiY3VycmVudCIsIFR5cGUpIH4gIkN1cnJlbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTWVhbiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1UeXBlKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gRXN0aW1hdGUsIAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gYFBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHNgKSAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhcix5PU1lYW4pKSArCiAgZ2VvbV9saW5lKGFlcyhsaW5ldHlwZT1Vc2VyKSkgKwogIGdlb21fbGluZXJhbmdlKGFlcyh5bWluID0gTG93ZXIsIHltYXggPSBVcHBlciksIHNpemUgPSAxLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoMiwxKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB2X2NvbG9ycykgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCw3MCxieT0xMCksCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDAsNzAsYnk9MTApLAogICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCw3MCkpICsKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKHRpdGxlID0gIlRvYmFjY28gcHJvZHVjdCB1c2VycyBtb3JlIHByZXZhbGVudCBhZnRlciAyMDE3IiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKcGxvdEFfdwoKIyMgQVZPQ0FETzogdXBkYXRlZCB2ZXJzaW9uIHVzaW5nIGdyb3VwX21vZGlmeQpwbG90QV93IDwtIG55dHNfZGF0YSAlPiUgCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgZ3JvdXBfbW9kaWZ5KH5zdXJ2ZXlNZWFuQSgueCkpICU+JQogIGRwbHlyOjpzZWxlY3QoLVR5cGUpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBFc3RpbWF0ZSwgCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2ApICU+JQogIGdncGxvdChhZXMoeD15ZWFyLHk9TWVhbikpICsKICBnZW9tX2xpbmUoYWVzKGxpbmV0eXBlPVVzZXIpKSArCiAgZ2VvbV9saW5lcmFuZ2UoYWVzKHltaW4gPSBMb3dlciwgeW1heCA9IFVwcGVyKSwgc2l6ZSA9IDEsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygyLDEpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHZfY29sb3JzKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDcwLGJ5PTEwKSwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMCw3MCxieT0xMCksCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLDcwKSkgKwogICAgdGhlbWVfbGluZWRyYXcoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSAiVG9iYWNjbyBwcm9kdWN0IHVzZXJzIG1vcmUgcHJldmFsZW50IGFmdGVyIDIwMTciLAogICAgICAgICB5ID0gIiUgb2Ygc3R1ZGVudHMiKQpwbG90QV93CgpgYGAKCk5vdyB3ZSBjYW4gc2VlIHRoYXQgd2UgaGF2ZSBjb25maWRlbmNlIGludGVydmFsIHJhbmdlcyBwbG90dGVkIGZvciBlYWNoIHZhbHVlLiAKCldlIHdpbGwgbWFrZSBhIHNpbWlsYXIgcGxvdCBmb3Igc3R1ZGVudHMgd2hvIHJlcG9ydGVkIGV2ZXIgdHJ5aW5nIG9yIHdobyBjdXJyZW50bHkgdXNlIGUtY2lnYXJldHRlcyBhcyBvcHBvc2VkIHRvIHRvYmFjY28gaW4gZ2VuZXJhbC4KCmBgYHtyfQpzdXJ2ZXlNZWFuQiA8LSBmdW5jdGlvbihjdXJyWWVhcil7CiAgb3B0aW9ucyhzdXJ2ZXkubG9uZWx5LnBzdSA9ICJhdmVyYWdlIikKICBjdXJyWWVhciAlPiUKICBhc19zdXJ2ZXlfZGVzaWduKHN0cmF0YSA9IHN0cmF0dW0sIAogICAgICAgICAgICAgICAgICAgICAgaWRzID0gcHN1LCAKICAgICAgICAgICAgICAgICAgd2VpZ2h0ICA9IGZpbndndCwgCiAgICAgICAgICAgICAgICAgICAgIG5lc3QgPSBUUlVFKSAlPiUKICBzdW1tYXJpemUoZWNpZ19ldmVyX3llYXIgPSBzdXJ2ZXlfbWVhbihlY2lnX2V2ZXIsIHZhcnR5cGUgPSAiY2kiLCBuYS5ybT1UUlVFKSwKICAgICAgICAgICAgbm9uX2VjaWdfZXZlcl95ZWFyID0gc3VydmV5X21lYW4obm9uX2VjaWdfZXZlciwgdmFydHlwZSA9ICJjaSIsIG5hLnJtPVRSVUUpKSAlPiUgIAogIG11dGF0ZV9hbGwoIioiLCAxMDApICU+JQogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksIAogICAgICAgICAgIG5hbWVzX3RvID0gIkNhdGVnb3J5IiwgCiAgICAgICAgICB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpICU+JQogICAgbXV0YXRlKEVzdGltYXRlID0gY2FzZV93aGVuKGdyZXBsKCJfbG93IiwgQ2F0ZWdvcnkpIH4gIkxvd2VyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiX3VwcCIsIENhdGVnb3J5KSB+ICJVcHBlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJNZWFuIiksCiAgICAgICAgIFVzZXIgPSBjYXNlX3doZW4oZ3JlcGwoImV2ZXIiLCBDYXRlZ29yeSkgfiAiRXZlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoImN1cnJlbnQiLCBDYXRlZ29yeSkgfiAiQ3VycmVudCIpLAogICAgICAgICBQcm9kdWN0ID0gY2FzZV93aGVuKGdyZXBsKCJub25fZWNpZyIsIENhdGVnb3J5KSB+ICJPdGhlciBwcm9kdWN0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJFLWNpZ2FyZXR0ZXMiKSkgJT4lCiAgZHBseXI6OnNlbGVjdCgtQ2F0ZWdvcnkpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBFc3RpbWF0ZSwgCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2ApCgp9CgpueXRzX2RhdGEgJT4lIAogIGdyb3VwX2J5KHllYXIpICU+JQogIGdyb3VwX21vZGlmeSh+c3VydmV5TWVhbkIoLngpKSAlPiUKICBoZWFkKCkKCiMjIEFWT0NBRE86IERyb3AgdGhpcyB2ZXJzaW9uIG9mIGNvZGUKbnl0c19kYXRhICU+JQogIGFzX3N1cnZleV9kZXNpZ24oc3RyYXRhID0gc3RyYXR1bSwgaWRzID0gcHN1LCB3ZWlnaHQgID0gZmlud2d0LCBuZXN0PVRSVUUpICU+JQogICAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgICAgIHN1bW1hcml6ZShlY2lnX2V2ZXJfeWVhciA9IHN1cnZleV9tZWFuKGVjaWdfZXZlciwgdmFydHlwZSA9ICJjaSIsIG5hLnJtPVRSVUUpLAogICAgICAgICAgICBub25fZWNpZ19ldmVyX3llYXIgPSBzdXJ2ZXlfbWVhbihub25fZWNpZ19ldmVyLCB2YXJ0eXBlID0gImNpIiwgbmEucm09VFJVRSkpICU+JSAgbXV0YXRlX2F0KHZhcnMoLXllYXIpLCAiKiIsIDEwMCkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAteWVhciwgCiAgICAgICAgICAgbmFtZXNfdG8gPSAiQ2F0ZWdvcnkiLCAKICAgICAgICAgIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgICBtdXRhdGUoRXN0aW1hdGUgPSBjYXNlX3doZW4oZ3JlcGwoIl9sb3ciLCBDYXRlZ29yeSkgfiAiTG93ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJfdXBwIiwgQ2F0ZWdvcnkpIH4gIlVwcGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk1lYW4iKSwKICAgICAgICAgVXNlciA9IGNhc2Vfd2hlbihncmVwbCgiZXZlciIsIENhdGVnb3J5KSB+ICJFdmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiY3VycmVudCIsIENhdGVnb3J5KSB+ICJDdXJyZW50IiksCiAgICAgICAgIFByb2R1Y3QgPSBjYXNlX3doZW4oZ3JlcGwoIm5vbl9lY2lnIiwgQ2F0ZWdvcnkpIH4gIk90aGVyIHByb2R1Y3RzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIkUtY2lnYXJldHRlcyIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1DYXRlZ29yeSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEVzdGltYXRlLCAKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IGBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCkgJT4lCiAgaGVhZCgpCgoKIyMgQVZPQ0FETzogRHJvcCB0aGlzIHZlcnNpb24gb2YgcGxvdApwbG90Ql93IDwtIG55dHNfZGF0YSAlPiUKICBhc19zdXJ2ZXlfZGVzaWduKHN0cmF0YSA9IHN0cmF0dW0sIGlkcyA9IHBzdSwgd2VpZ2h0ICA9IGZpbndndCwgbmVzdD1UUlVFKSAlPiUKICAgIGdyb3VwX2J5KHllYXIpICU+JQpzdW1tYXJpemUoZWNpZ19ldmVyX3llYXIgPSBzdXJ2ZXlfbWVhbihlY2lnX2V2ZXIsIHZhcnR5cGUgPSAiY2kiLCBuYS5ybT1UUlVFKSwKICAgICAgICAgICAgbm9uX2VjaWdfZXZlcl95ZWFyID0gc3VydmV5X21lYW4obm9uX2VjaWdfZXZlciwgdmFydHlwZSA9ICJjaSIsIG5hLnJtPVRSVUUpKSAlPiUgIG11dGF0ZV9hdCh2YXJzKC15ZWFyKSwgIioiLCAxMDApICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLXllYXIsIAogICAgICAgICAgIG5hbWVzX3RvID0gIkNhdGVnb3J5IiwgCiAgICAgICAgICB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpICU+JQogICAgbXV0YXRlKEVzdGltYXRlID0gY2FzZV93aGVuKGdyZXBsKCJfbG93IiwgQ2F0ZWdvcnkpIH4gIkxvd2VyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiX3VwcCIsIENhdGVnb3J5KSB+ICJVcHBlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJNZWFuIiksCiAgICAgICAgIFVzZXIgPSBjYXNlX3doZW4oZ3JlcGwoImV2ZXIiLCBDYXRlZ29yeSkgfiAiRXZlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoImN1cnJlbnQiLCBDYXRlZ29yeSkgfiAiQ3VycmVudCIpLAogICAgICAgICBQcm9kdWN0ID0gY2FzZV93aGVuKGdyZXBsKCJub25fZWNpZyIsIENhdGVnb3J5KSB+ICJPdGhlciBwcm9kdWN0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJFLWNpZ2FyZXR0ZXMiKSkgJT4lCiAgZHBseXI6OnNlbGVjdCgtQ2F0ZWdvcnkpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBFc3RpbWF0ZSwgCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2ApICU+JQogIGdncGxvdChhZXMoeD15ZWFyLHk9TWVhbiwgY29sb3IgPSBQcm9kdWN0KSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX2xpbmVyYW5nZShhZXMoeW1pbiA9IExvd2VyLCB5bWF4ID0gVXBwZXIpLCBzaXplID0gMSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsMSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdl9jb2xvcnMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsNjAsYnk9MTApLAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgwLDYwLGJ5PTEwKSwKICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsNjApKSArCiAgICB0aGVtZV9saW5lZHJhdygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh0aXRsZSA9ICIlIEV2ZXIgdHJ5aW5nIGUtY2lnYXJldHRlcyBpbmNyZWFzZXMgJlxuJSBFdmVyIHRyeWluZyBvdGhlciBwcm9kdWN0cyBkZWNyZWFzZXMiLAogICAgICAgICB5ID0gIiUgb2Ygc3R1ZGVudHMiKQoKcGxvdEJfdwoKcGxvdEJfdyA8LSBueXRzX2RhdGEgJT4lIAogIGdyb3VwX2J5KHllYXIpICU+JQogIGdyb3VwX21vZGlmeSh+c3VydmV5TWVhbkIoLngpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhcix5PU1lYW4sIGNvbG9yID0gUHJvZHVjdCkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9saW5lcmFuZ2UoYWVzKHltaW4gPSBMb3dlciwgeW1heCA9IFVwcGVyKSwgc2l6ZSA9IDEsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygyLDEpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHZfY29sb3JzKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDYwLGJ5PTEwKSwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMCw2MCxieT0xMCksCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLDYwKSkgKwogICAgdGhlbWVfbGluZWRyYXcoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSAiJSBFdmVyIHRyeWluZyBlLWNpZ2FyZXR0ZXMgaW5jcmVhc2VzICZcbiUgRXZlciB0cnlpbmcgb3RoZXIgcHJvZHVjdHMgZGVjcmVhc2VzIiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnBsb3RCX3cKCmBgYAoKCk5vdyB3ZSB3aWxsIGRvIHRoZSBzYW1lIGJ1dCBmb3IgY3VycmVudCB1c2VyczoKCmBgYHtyfQpzdXJ2ZXlNZWFuQyA8LSBmdW5jdGlvbihjdXJyWWVhcil7CiAgb3B0aW9ucyhzdXJ2ZXkubG9uZWx5LnBzdSA9ICJhdmVyYWdlIikKICBjdXJyWWVhciAlPiUKICBhc19zdXJ2ZXlfZGVzaWduKHN0cmF0YSA9IHN0cmF0dW0sIAogICAgICAgICAgICAgICAgICAgICAgaWRzID0gcHN1LCAKICAgICAgICAgICAgICAgICAgd2VpZ2h0ICA9IGZpbndndCwgCiAgICAgICAgICAgICAgICAgICAgIG5lc3QgPSBUUlVFKSAlPiUKICAgICAgIHN1bW1hcml6ZShlY2lnX2N1cnJlbnRfeWVhciA9IHN1cnZleV9tZWFuKGVjaWdfY3VycmVudCwgdmFydHlwZSA9ICJjaSIsIG5hLnJtPVRSVUUpLAogICAgICAgICAgICBub25fZWNpZ19jdXJyZW50X3llYXIgPSBzdXJ2ZXlfbWVhbihub25fZWNpZ19jdXJyZW50LCB2YXJ0eXBlID0gImNpIiwgbmEucm09VFJVRSkpICU+JQogIG11dGF0ZV9hbGwoIioiLCAxMDApICU+JQogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksIAogICAgICAgICAgIG5hbWVzX3RvID0gIkNhdGVnb3J5IiwgCiAgICAgICAgICB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpICU+JQogICAgbXV0YXRlKEVzdGltYXRlID0gY2FzZV93aGVuKGdyZXBsKCJfbG93IiwgQ2F0ZWdvcnkpIH4gIkxvd2VyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiX3VwcCIsIENhdGVnb3J5KSB+ICJVcHBlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJNZWFuIiksCiAgICAgICAgIFVzZXIgPSBjYXNlX3doZW4oZ3JlcGwoImV2ZXIiLCBDYXRlZ29yeSkgfiAiRXZlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoImN1cnJlbnQiLCBDYXRlZ29yeSkgfiAiQ3VycmVudCIpLAogICAgICAgICBQcm9kdWN0ID0gY2FzZV93aGVuKGdyZXBsKCJub25fZWNpZyIsIENhdGVnb3J5KSB+ICJPdGhlciBwcm9kdWN0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJFLWNpZ2FyZXR0ZXMiKSkgJT4lCiAgZHBseXI6OnNlbGVjdCgtQ2F0ZWdvcnkpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBFc3RpbWF0ZSwgCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2ApCgp9CgojQVZPQ0FETzogRHJvcCB0aGlzIHZlcnNpb24gb2YgcGxvdCBjb2RlCnBsb3RDX3cgPC0gbnl0c19kYXRhICU+JQogIGFzX3N1cnZleV9kZXNpZ24oc3RyYXRhID0gc3RyYXR1bSwgaWRzID0gcHN1LCB3ZWlnaHQgID0gZmlud2d0LCBuZXN0PVRSVUUpICU+JQogICAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgICAgICBzdW1tYXJpemUoZWNpZ19jdXJyZW50X3llYXIgPSBzdXJ2ZXlfbWVhbihlY2lnX2N1cnJlbnQsIHZhcnR5cGUgPSAiY2kiLCBuYS5ybT1UUlVFKSwKICAgICAgICAgICAgbm9uX2VjaWdfY3VycmVudF95ZWFyID0gc3VydmV5X21lYW4obm9uX2VjaWdfY3VycmVudCwgdmFydHlwZSA9ICJjaSIsIG5hLnJtPVRSVUUpKSAlPiUKICAgICAgIG11dGF0ZV9hdCh2YXJzKC15ZWFyKSwgIioiLCAxMDApICU+JQogICAgICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAteWVhciwKICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJDYXRlZ29yeSIsIAogICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgICAgICBtdXRhdGUoRXN0aW1hdGUgPSBjYXNlX3doZW4oZ3JlcGwoIl9sb3ciLCBDYXRlZ29yeSkgfiAiTG93ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJfdXBwIiwgQ2F0ZWdvcnkpIH4gIlVwcGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk1lYW4iKSwKICAgICAgICAgVXNlciA9IGNhc2Vfd2hlbihncmVwbCgiZXZlciIsIENhdGVnb3J5KSB+ICJFdmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiY3VycmVudCIsIENhdGVnb3J5KSB+ICJDdXJyZW50IiksCiAgICAgICAgIFByb2R1Y3QgPSBjYXNlX3doZW4oZ3JlcGwoIm5vbl9lY2lnIiwgQ2F0ZWdvcnkpIH4gIk90aGVyIHByb2R1Y3RzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIkUtY2lnYXJldHRlcyIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1DYXRlZ29yeSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEVzdGltYXRlLCAKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IGBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCkgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9eWVhcix5PU1lYW4sIGNvbG9yPVByb2R1Y3QpKSArCiAgZ2VvbV9saW5lKGFlcyhsaW5ldHlwZT0iZGFzaGVkIikpICsKICBnZW9tX2xpbmVyYW5nZShhZXMoeW1pbiA9IExvd2VyLCB5bWF4ID0gVXBwZXIpLCBzaXplID0gMSwgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygyLDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA2MCwgYnkgPSAxMCksIGxpbWl0cyA9IGMoMCw2MCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdl9jb2xvcnMpICsKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKHRpdGxlID0gIiUgQ3VycmVudGx5IHVzaW5nIGUtY2lnYXJldHRlcyBpbmNyZWFzZXMgJlxuJSBDdXJyZW50bHkgdXNpbmcgb3RoZXIgcHJvZHVjdHMgZGVjcmVhc2VzIiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKcGxvdENfdwoKcGxvdENfdyA8LSBueXRzX2RhdGEgJT4lIAogIGdyb3VwX2J5KHllYXIpICU+JQogIGdyb3VwX21vZGlmeSh+c3VydmV5TWVhbkMoLngpKSAlPiUKICAgIGdncGxvdChhZXMoeD15ZWFyLHk9TWVhbiwgY29sb3I9UHJvZHVjdCkpICsKICBnZW9tX2xpbmUoYWVzKGxpbmV0eXBlPSJkYXNoZWQiKSkgKwogIGdlb21fbGluZXJhbmdlKGFlcyh5bWluID0gTG93ZXIsIHltYXggPSBVcHBlciksIHNpemUgPSAxLCAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsMSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDYwLCBieSA9IDEwKSwgbGltaXRzID0gYygwLDYwKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB2X2NvbG9ycykgKwogICAgdGhlbWVfbGluZWRyYXcoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSAiJSBDdXJyZW50bHkgdXNpbmcgZS1jaWdhcmV0dGVzIGluY3JlYXNlcyAmXG4lIEN1cnJlbnRseSB1c2luZyBvdGhlciBwcm9kdWN0cyBkZWNyZWFzZXMiLAogICAgICAgICB5ID0gIiUgb2Ygc3R1ZGVudHMiKQpwbG90Q193CgoKYGBgCgoKTm93IHdlIHdpbGwgcHV0IHRoZXNlIHBsb3RzIHRvZ2V0aGVyIGFnYWluIHVzaW5nIHRoZSBgY293cGxvdGAgcGFja2FnZToKCmBgYHtyfQp0aXRsZV93IDwtIGdnZHJhdygpICsgCiAgZHJhd19sYWJlbCgKICAgIGV4cHJlc3Npb24oIldoYXQgaXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHZhcGluZyByYXRlcyBhbmQgdG9iYWNjbyB1c2U/IiksCiAgICBmb250ZmFjZSA9ICdib2xkJywKICAgIHNpemU9MTQsCiAgICB4ID0gMCwKICAgIGhqdXN0ID0gMAogICkgKwogIHRoZW1lKAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCkKICApCgpwbG90c0FfdyA8LSBwbG90X2dyaWQocGxvdEFfdywKICAgICAgICAgICAgICAgICAgICAgcmVsX3dpZHRocyA9IGMoMSksCiAgICAgICAgICAgICAgICAgICAgIGFsaWduID0gInYiLAogICAgICAgICAgICAgICAgICAgICBheGlzID0gImJ0IikKcGxvdHNCQ193IDwtIHBsb3RfZ3JpZChwbG90Ql93LAogICAgICAgICAgICAgICAgICAgICBwbG90Q193LAogICAgICAgICAgICAgICAgICAgICByZWxfd2lkdGhzID0gYygxLDEpLAogICAgICAgICAgICAgICAgICAgICBhbGlnbiA9ICJ2IiwKICAgICAgICAgICAgICAgICAgICAgYXhpcyA9ICJidCIpCgpsZWdlbmRfdyA8LSBnZXRfbGVnZW5kKHBsb3QxYyArCiAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikpCgpmaWd1cmVfdyA8LSBwbG90X2dyaWQodGl0bGVfdywKICAgICAgICAgICAgICAgICAgICAgIHBsb3RzQV93LAogICAgICAgICAgICAgICAgICAgICAgcGxvdHNCQ193LAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX3csCiAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMSwKICAgICAgICAgICAgICAgICAgICAgIHJlbF9oZWlnaHRzID0gYygwLjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAuMSksCiAgICAgICAgICAgICAgICAgICAgICBzY2FsZSA9IDEuMCkKCmZpZ3VyZV93CmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZXNlIGZpZ3VyZXMgbG9vayBxdWl0ZSBzaW1pbGFyIHRvIHRoZSBvbmVzIGdlbmVyYXRlZCB3aXRob3V0IHVzaW5nIHRoZSBzdXJ2ZXkgd2VpZ2h0cy4KCiMjIyBBcnRpZmljaWFsIENvaG9ydAoKQWx0aG91Z2ggdGhlIHN1cnZleSBkZXNpZ24gZG9lcyBub3QgYWxsb3cgc3BlY2lmaWMgaW5kaXZpZHVhbHMgdG8gYmUgZm9sbG93ZWQgb3ZlciB0aW1lLCB3ZSB3aWxsIHVzZSBjZXJ0YWluIHN1YnNldHMgb2YgdGhlIGRhdGEgZnJvbSBlYWNoIHllYXIgdG8gY29uc3RydWN0IGFuIGFydGlmaWNpYWwgY29ob3J0IHdoZXJlIHdlIGZvbGxvdyBzdHVkZW50cyBvZiB0aGUgc2FtZSBhZ2UgZ3JvdXAgYXMgdGhleSBnZXQgb2xkZXIuIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBsb29rIGF0IGhvdyB0b2JhY2NvIHVzYWdlIGNoYW5nZWQgZm9yIHN0dWRlbnRzIHdobyB3ZXJlIGluIDh0aCBncmFkZSBpbiAyMDE1IGFzIHRoZXkgYWdlZC4gCgpBbGwgb2YgdGhlIGRhdGEgc28gZmFyIGhhcyBpbmNsdWRlZCBhbGwgNnRoLTEydGggZ3JhZGVycyBldmVyeSB5ZWFyLiBOb3cgd2Ugd2lsbCBsb29rIGF0IGp1c3QgdGhlIGRhdGEgZm9yIHN0dWRlbnRzIGV4cGVjdGVkIHRvIGdyYWR1YXRlIGluIDIwMTkuIFRoZXNlIGFyZSB0aGUgc3R1ZGVudHMgd2hvIHdlcmUgaW4gOHRoIGdyYWRlIGluIDIwMTUsIG1vc3Qgb2Ygd2hvbSB3ZXJlIDl0aCBncmFkZXJzIGluIDIwMTYsIDEwdGggZ3JhZGVycyBpbiAyMDE3IGFuZCBzbyBvbi4gV2Ugd2lsbCBmaWx0ZXIgdGhlIGRhdGEgdG8ganVzdCB0aGUgc3R1ZGVudHMgZXhwZWN0ZWQgdG8gYmUgaW4gdGhlIGdyYWR1YXRpbmcgY2xhc3Mgb2YgMjAxOS4KCgpgYGB7cn0KCnN1cnZleU1lYW5Db2hvcnQgPC0gZnVuY3Rpb24oY3VyclllYXIpewogIG9wdGlvbnMoc3VydmV5LmxvbmVseS5wc3UgPSAiYXZlcmFnZSIpCiAgY3VyclllYXIgJT4lCiAgYXNfc3VydmV5X2Rlc2lnbihzdHJhdGEgPSBzdHJhdHVtLCAKICAgICAgICAgICAgICAgICAgICAgIGlkcyA9IHBzdSwgCiAgICAgICAgICAgICAgICAgIHdlaWdodCAgPSBmaW53Z3QsIAogICAgICAgICAgICAgICAgICAgICBuZXN0ID0gVFJVRSkgJT4lCnN1bW1hcml6ZShlY2lnX2V2ZXJfeWVhciA9IHN1cnZleV9tZWFuKGVjaWdfZXZlciwgdmFydHlwZSA9ICJjaSIsIG5hLnJtPVRSVUUpLAogICAgICAgICAgICBlY2lnX2N1cnJlbnRfeWVhciA9IHN1cnZleV9tZWFuKGVjaWdfY3VycmVudCwgdmFydHlwZSA9ICJjaSIsIG5hLnJtPVRSVUUpLAogICAgICAgICAgICBub25fZWNpZ19ldmVyX3llYXIgPSBzdXJ2ZXlfbWVhbihub25fZWNpZ19ldmVyLCB2YXJ0eXBlID0gImNpIiwgbmEucm09VFJVRSksCiAgICAgICAgICAgIG5vbl9lY2lnX2N1cnJlbnRfeWVhciA9IHN1cnZleV9tZWFuKG5vbl9lY2lnX2N1cnJlbnQsIHZhcnR5cGUgPSAiY2kiLCBuYS5ybT1UUlVFKSwKICAgICAgICAgIHRvYmFjY29fZXZlcl95ZWFyID0gc3VydmV5X21lYW4odG9iYWNjb19ldmVyLCB2YXJ0eXBlID0gImNpIiwgbmEucm09VFJVRSksCiAgICAgICAgICAgIHRvYmFjY29fY3VycmVudF95ZWFyID0gc3VydmV5X21lYW4odG9iYWNjb19jdXJyZW50LCB2YXJ0eXBlID0gImNpIiwgbmEucm09VFJVRSkpJT4lCiAgbXV0YXRlX2FsbCgiKiIsIDEwMCkgJT4lCiAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgCiAgICAgICAgICAgbmFtZXNfdG8gPSAiQ2F0ZWdvcnkiLCAKICAgICAgICAgIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgICBtdXRhdGUoRXN0aW1hdGUgPSBjYXNlX3doZW4oZ3JlcGwoIl9sb3ciLCBDYXRlZ29yeSkgfiAiTG93ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJfdXBwIiwgQ2F0ZWdvcnkpIH4gIlVwcGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk1lYW4iKSwKICAgICAgICAgVXNlciA9IGNhc2Vfd2hlbihncmVwbCgiZXZlciIsIENhdGVnb3J5KSB+ICJFdmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiY3VycmVudCIsIENhdGVnb3J5KSB+ICJDdXJyZW50IiksCiAgICAgICAgIFByb2R1Y3QgPSBjYXNlX3doZW4oZ3JlcGwoIm5vbl9lY2lnIiwgQ2F0ZWdvcnkpIH4gIk90aGVyIHByb2R1Y3RzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgidG9iYWNjbyIsIENhdGVnb3J5KSB+ICJBbnkgdG9iYWNjbyBwcm9kdWN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIkUtY2lnYXJldHRlcyIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1DYXRlZ29yeSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEVzdGltYXRlLCAKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IGBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCkKCn0KCkNvaG9ydF9kYXRhIDwtbnl0c19kYXRhICU+JQogIGZpbHRlcigoR3JhZGUgPT0gIjgiICYgeWVhciA9PSAyMDE1KSB8CiAgICAgICAgIChHcmFkZSA9PSAiOSIgJiB5ZWFyID09IDIwMTYpIHwKICAgICAgICAgKEdyYWRlID09ICIxMCIgJiB5ZWFyID09IDIwMTcpIHwKICAgICAgICAgKEdyYWRlID09ICIxMSIgJiB5ZWFyID09IDIwMTgpIHwKICAgICAgICAgIChHcmFkZSA9PSAiMTIiICYgeWVhciA9PSAyMDE5KSAKICAgICAgICAgKSAlPiUKICBhc19zdXJ2ZXlfZGVzaWduKHN0cmF0YSA9IHN0cmF0dW0sIGlkcyA9IHBzdSwgd2VpZ2h0ICA9IGZpbndndCkgJT4lCiAgICBncm91cF9ieSh5ZWFyKSAlPiUKc3VtbWFyaXplKGVjaWdfZXZlcl95ZWFyID0gc3VydmV5X21lYW4oZWNpZ19ldmVyLCB2YXJ0eXBlID0gImNpIiwgbmEucm09VFJVRSksCiAgICAgICAgICAgIGVjaWdfY3VycmVudF95ZWFyID0gc3VydmV5X21lYW4oZWNpZ19jdXJyZW50LCB2YXJ0eXBlID0gImNpIiwgbmEucm09VFJVRSksCiAgICAgICAgICAgIG5vbl9lY2lnX2V2ZXJfeWVhciA9IHN1cnZleV9tZWFuKG5vbl9lY2lnX2V2ZXIsIHZhcnR5cGUgPSAiY2kiLCBuYS5ybT1UUlVFKSwKICAgICAgICAgICAgbm9uX2VjaWdfY3VycmVudF95ZWFyID0gc3VydmV5X21lYW4obm9uX2VjaWdfY3VycmVudCwgdmFydHlwZSA9ICJjaSIsIG5hLnJtPVRSVUUpLAogICAgICAgICAgdG9iYWNjb19ldmVyX3llYXIgPSBzdXJ2ZXlfbWVhbih0b2JhY2NvX2V2ZXIsIHZhcnR5cGUgPSAiY2kiLCBuYS5ybT1UUlVFKSwKICAgICAgICAgICAgdG9iYWNjb19jdXJyZW50X3llYXIgPSBzdXJ2ZXlfbWVhbih0b2JhY2NvX2N1cnJlbnQsIHZhcnR5cGUgPSAiY2kiLCBuYS5ybT1UUlVFKSklPiUKICBtdXRhdGVfYXQodmFycygteWVhciksICIqIiwgMTAwKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC15ZWFyLCBuYW1lc190byA9ICJDYXRlZ29yeSIsIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIiklPiUKICAgIG11dGF0ZShFc3RpbWF0ZSA9IGNhc2Vfd2hlbihncmVwbCgiX2xvdyIsIENhdGVnb3J5KSB+ICJMb3dlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIl91cHAiLCBDYXRlZ29yeSkgfiAiVXBwZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTWVhbiIpLAogICAgICAgICBVc2VyID0gY2FzZV93aGVuKGdyZXBsKCJldmVyIiwgQ2F0ZWdvcnkpIH4gIkV2ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJjdXJyZW50IiwgQ2F0ZWdvcnkpIH4gIkN1cnJlbnQiKSwKICAgICAgICAgUHJvZHVjdCA9IGNhc2Vfd2hlbihncmVwbCgibm9uX2VjaWciLCBDYXRlZ29yeSkgfiAiT3RoZXIgcHJvZHVjdHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJ0b2JhY2NvIiwgQ2F0ZWdvcnkpIH4gIkFueSB0b2JhY2NvIHByb2R1Y3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiRS1jaWdhcmV0dGVzIikpICU+JQogIGRwbHlyOjpzZWxlY3QoLUNhdGVnb3J5KSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gRXN0aW1hdGUsIAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gYFBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHNgKQoKaGVhZChDb2hvcnRfZGF0YSkKCgpDb2hvcnRfZGF0YSA8LW55dHNfZGF0YSAlPiUKICBmaWx0ZXIoKEdyYWRlID09ICI4IiAmIHllYXIgPT0gMjAxNSkgfAogICAgICAgICAoR3JhZGUgPT0gIjkiICYgeWVhciA9PSAyMDE2KSB8CiAgICAgICAgIChHcmFkZSA9PSAiMTAiICYgeWVhciA9PSAyMDE3KSB8CiAgICAgICAgIChHcmFkZSA9PSAiMTEiICYgeWVhciA9PSAyMDE4KSB8CiAgICAgICAgICAoR3JhZGUgPT0gIjEyIiAmIHllYXIgPT0gMjAxOSkgCiAgICAgICAgICkgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiBncm91cF9tb2RpZnkofnN1cnZleU1lYW5Db2hvcnQoLngpKQoKaGVhZChDb2hvcnRfZGF0YSkKCmBgYAoKV2Ugd2lsbCBub3cgbWFrZSBzaW1pbGFyIHBsb3RzIHRvIHRob3NlIGFib3ZlIGZvciB0aGlzIHN1YnNldCBvZiB0aGUgZGF0YToKCmBgYHtyfQpwbG90QV93XzggPC1Db2hvcnRfZGF0YSAlPiUKICBmaWx0ZXIoUHJvZHVjdCA9PSAiQW55IHRvYmFjY28gcHJvZHVjdCIpICU+JQogIGdncGxvdChhZXMoeD15ZWFyLHk9TWVhbikpICsKICBnZW9tX2xpbmUoYWVzKGxpbmV0eXBlPVVzZXIpKSArCiAgZ2VvbV9saW5lcmFuZ2UoYWVzKHltaW4gPSBMb3dlciwgeW1heCA9IFVwcGVyKSwgc2l6ZSA9IDEpICsgCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoMiwxKSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDcwLGJ5PTEwKSwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMCw3MCxieT0xMCksCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLDcwKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB2X2NvbG9ycykgKwogICAgdGhlbWVfbGluZWRyYXcoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSAiVG9iYWNjbyBwcm9kdWN0IHVzZSBiZWNhbWUgaW5jcmVhc2luZ2x5IHByZXZhbGVudCIsCiAgICAgICAgIHkgPSAiJSBvZiBzdHVkZW50cyIpCgpwbG90Ql93XzggPC1Db2hvcnRfZGF0YSAlPiUKICBmaWx0ZXIoUHJvZHVjdCAhPSAiQW55IHRvYmFjY28gcHJvZHVjdCIsIFVzZXIgPT0gIkV2ZXIiKSAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhcix5PU1lYW4sIGNvbG9yPVByb2R1Y3QpKSArCiAgZ2VvbV9saW5lKGxpbmV0eXBlPTEpICsKICBnZW9tX2xpbmVyYW5nZShhZXMoeW1pbiA9IExvd2VyLCB5bWF4ID0gVXBwZXIpLCBzaXplID0gMSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDEwLCA2MCwgYnkgPSAxMCksIGxpbWl0cyA9IGMoMTAsNjApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHZfY29sb3JzKSArCiAgICB0aGVtZV9saW5lZHJhdygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh0aXRsZSA9ICIlIGV2ZXIgdHJ5aW5nIHRvYmFjY28gcHJvZHVjdHMgaW5jcmVhc2VzIiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnBsb3RDX3dfOCA8LUNvaG9ydF9kYXRhICU+JQogIGZpbHRlcihQcm9kdWN0ICE9ICJBbnkgdG9iYWNjbyBwcm9kdWN0IiwgVXNlciA9PSAiQ3VycmVudCIpICU+JQogICAgZ2dwbG90KGFlcyh4PXllYXIseT1NZWFuLCBjb2xvcj1Qcm9kdWN0KSkgKwogIGdlb21fbGluZShhZXMobGluZXR5cGU9VXNlcikpICsKICBnZW9tX2xpbmVyYW5nZShhZXMoeW1pbiA9IExvd2VyLCB5bWF4ID0gVXBwZXIpLCBzaXplID0gMSkgKyAKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygyLDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA2MCwgYnkgPSAxMCksIGxpbWl0cyA9IGMoMCw2MCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdl9jb2xvcnMpICsKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKHRpdGxlID0gIkUtY2lnYXJldHRlIHVzZSBzdXJwYXNzZXMgdXNlIG9mIG90aGVyIHByb2R1Y3RzIiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnRpdGxlX3dfOCA8LSBnZ2RyYXcoKSArIAogIGRyYXdfbGFiZWwoCiAgICBleHByZXNzaW9uKCJBbW9uZyBzdHVkZW50cyBleHBlY3RlZCB0byBiZSBpbiB0aGUgZ3JhZHVhdGluZyBjbGFzcyBvZiAyMDE5LCBob3cgYXJlIHZhcGluZyByYXRlcyByZWxhdGVkIHRvIHRvYmFjY28gdXNlPyIpLAogICAgZm9udGZhY2UgPSAnYm9sZCcsCiAgICBzaXplPTE0LAogICAgeCA9IDAsCiAgICBoanVzdCA9IDAKICApICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKcGxvdHNBX3dfOCA8LSBwbG90X2dyaWQocGxvdEFfd184LAogICAgICAgICAgICAgICAgICAgICAgICByZWxfd2lkdGhzID0gYygxKSwKICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ24gPSAidiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMgPSAiYnQiKQoKcGxvdHNCQ193XzggPC0gcGxvdF9ncmlkKHBsb3RCX3dfOCwKICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RDX3dfOCwKICAgICAgICAgICAgICAgICAgICAgICAgIHJlbF93aWR0aHMgPSBjKDEsMSksCiAgICAgICAgICAgICAgICAgICAgICAgICBheGlzID0gImJ0IikKCmxlZ2VuZF93XzggPC0gZ2V0X2xlZ2VuZChwbG90MWMgKwogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpKQoKZmlndXJlX3dfOCA8LSBwbG90X2dyaWQodGl0bGVfd184LAogICAgICAgICAgICAgICAgICAgICAgICBwbG90c0Ffd184LAogICAgICAgICAgICAgICAgICAgICAgICBwbG90c0JDX3dfOCwKICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX3dfOCwKICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgIHJlbF9oZWlnaHRzID0gYygwLjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAuMSksCiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlID0gMS4wCikKCmZpZ3VyZV93XzgKYGBgCgojIyMgRmluYWwgRmlndXJlCgpGaW5hbGx5IHdlIHdpbGwgcHV0IG91ciBwbG90cyB0b2dldGhlciB0byBjcmVhdGUgYSBwbG90IHRoYXQgZGVzY3JpYmVzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBlLWNpZ2FyZXR0ZSB1c2FnZSBhbmQgb3ZlcmFsbCB0b2JhY2NvIHVzZSwgY29tYmluaW5nIGJvdGggb3VyIGZpcnN0IHNldCBvZiB1bndlaWdodGVkIHJlc3VsdHMsIGFuZCB0aG9zZSBjYWxjdWxhdGVkIHVzaW5nIHRoZSBgc3J2eXJgIHBhY2thZ2UuCgpgYGB7cn0KdGl0bGVfZmluYWwgPC0gZ2dkcmF3KCkgKwogIGRyYXdfbGFiZWwoCiAgICBleHByZXNzaW9uKCJXaGF0IGlzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB2YXBpbmcgcmF0ZXMgYW5kIHRvYmFjY28gdXNlPyIpLAogICAgZm9udGZhY2UgPSAnYm9sZCcsCiAgICBzaXplPTE2LAogICAgeCA9IDAuNSkgKwogIHRoZW1lKAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCkKICApCgpzdWJ0aXRsZV91d19maW5hbCA8LSBnZ2RyYXcoKSArIAogIGRyYXdfbGFiZWwoCiAgICBleHByZXNzaW9uKH42XnRofiItIn4xMl50aH4iZ3JhZGVycywgdW53ZWlnaHRlZCIpLAogICAgc2l6ZT0xMiwKICAgIHggPSAwLjUpICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKc3VidGl0bGVfd19maW5hbCA8LSBnZ2RyYXcoKSArIAogIGRyYXdfbGFiZWwoCiAgICBleHByZXNzaW9uKH42XnRofiItIn4xMl50aH4iZ3JhZGVycywgd2VpZ2h0ZWQiKSwKICAgIGZvbnRmYWNlID0gJ2JvbGQnLAogICAgc2l6ZT0xMiwKICAgIHggPSAwLjUpICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKc3VidGl0bGVfd184X2ZpbmFsIDwtIGdnZHJhdygpICsgCiAgZHJhd19sYWJlbCgKICAgIGV4cHJlc3Npb24oIkFwcHJveGltYXRlIGdyYWR1YXRpbmcgXG4gY2xhc3Mgb2YgMjAxOSwgd2VpZ2h0ZWQiKSwKICAgIGZvbnRmYWNlID0gJ2JvbGQnLAogICAgc2l6ZT0xMiwKICAgIHggPSAwLjUpICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKc3VidGl0bGVfZmluYWwgPC0gcGxvdF9ncmlkKHN1YnRpdGxlX3V3X2ZpbmFsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VidGl0bGVfd19maW5hbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnRpdGxlX3dfOF9maW5hbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzKQoKcGxvdHNBX3RpdGxlX2ZpbmFsIDwtIGdnZHJhdygpICsgCiAgZHJhd19sYWJlbCgKICAgIGV4cHJlc3Npb24oIlByZXZhbGVuY2Ugb2YgYW55IHRvYmFjY28gcHJvZHVjdCB1c2UgYnkgdXNlciB0eXBlIiksCiAgICBzaXplPTE0LAogICAgeCA9IDAuNSkgKwogIHRoZW1lKAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCkKICApCgpwbG90c0FfZmluYWwgPC0gcGxvdF9ncmlkKHBsb3RBX3V3ICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdEFfdyArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RBX3dfOCArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzLAogICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduID0gInYiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMgPSAiYnQiKQoKcGxvdHNCX3RpdGxlX2ZpbmFsIDwtIGdnZHJhdygpICsgCiAgZHJhd19sYWJlbCgKICAgIGV4cHJlc3Npb24oIlByZXZhbGVuY2Ugb2YgZXZlciB0cnlpbmcgYnkgcHJvZHVjdCB0eXBlIiksCiAgICBzaXplPTE0LAogICAgeCA9IDAuNSkgKwogIHRoZW1lKAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCkKICApCgpwbG90c0JfZmluYWwgPC0gcGxvdF9ncmlkKHBsb3RCX3V3ICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdEJfdyArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RCX3dfOCArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzLAogICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduID0gInYiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMgPSAiYnQiKQoKcGxvdHNDX3RpdGxlX2ZpbmFsIDwtIGdnZHJhdygpICsgCiAgZHJhd19sYWJlbCgKICAgIGV4cHJlc3Npb24oIlByZXZhbGVuY2Ugb2YgY3VycmVudCB1c2UgYnkgcHJvZHVjdCB0eXBlIiksCiAgICBzaXplPTE0LAogICAgeCA9IDAuNSkgKwogIHRoZW1lKAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCkKICApCgpwbG90c0NfZmluYWwgPC0gcGxvdF9ncmlkKHBsb3RDX3V3ICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdENfdyArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RDX3dfOCArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzLAogICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduID0gInYiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMgPSAiYnQiKQoKbGVnZW5kX2ZpbmFsIDwtIGdldF9sZWdlbmQocGxvdDFjICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSkKCmZpbmFsX3Bsb3QgPC0gcGxvdF9ncmlkKHRpdGxlX2ZpbmFsLAogICAgICAgICAgcGxvdHNBX3RpdGxlX2ZpbmFsLAogICAgICAgICAgc3VidGl0bGVfZmluYWwsCiAgICAgICAgICBwbG90c0FfZmluYWwsCiAgICAgICAgICBwbG90c0JfdGl0bGVfZmluYWwsCiAgICAgICAgICBzdWJ0aXRsZV9maW5hbCwKICAgICAgICAgIHBsb3RzQl9maW5hbCwKICAgICAgICAgIHBsb3RzQ190aXRsZV9maW5hbCwKICAgICAgICAgIHN1YnRpdGxlX2ZpbmFsLAogICAgICAgICAgcGxvdHNDX2ZpbmFsLAogICAgICAgICAgbGVnZW5kX2ZpbmFsLAogICAgICAgICAgbmNvbCA9IDEsCiAgICAgICAgICByZWxfaGVpZ2h0cyA9IGMoMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgIDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAwLjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAwLjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgMC4xLAogICAgICAgICAgICAgICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgIDAuMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAxLAogICAgICAgICAgICAgICAgICAgICAgICAgIDAuMSkpCgpmaW5hbF9wbG90CmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIGluY2x1ZGU9RkFMU0V9Cmdnc2F2ZShoZXJlOjpoZXJlKCJpbWciLCAiZmluYWxfcGxvdC5wbmciKSkKYGBgCgojIyAqKlN1Z2dlc3RlZCBIb21ld29yayoqCioqKiAKCjxzdHlsZT4KZGl2LmJsdWUgeyBiYWNrZ3JvdW5kLWNvbG9yOiNlNmYwZmY7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMjBweDt9Cjwvc3R5bGU+CjxkaXYgY2xhc3MgPSAiYmx1ZSI+CgorIENhbGN1bGF0ZSBjb25maWRlbmNlIGludGVydmFscyBmb3IgdGhlIHVud2VpZ2h0ZWQgZXN0aW1hdGVzIGFuZCBhZGQgdGhlIGFwcHJvcHJpYXRlIGVycm9yIGJhcnMgdG8gdGhlIG1haW4gZmlndXJlcy4KKyBBcHBseSBzdXJ2ZXkgd2VpZ2h0cyB0byBvbmUgb2YgdGhlIGZpZ3VyZXMgcHJvZHVjZWQgaW4gdGhpcyBjYXNlIHN0dWR5IGluIHdoaWNoIHdlaWdodGVkIGVzdGltYXRlcyB3ZXJlIG5vdCBwcm9kdWNlZC4gSW5jbHVkZSBlcnJvciBiYXJzIGluIHRoZSB1cGRhdGVkIGZpZ3VyZS4KICAgICsgRG9lcyB0aGUgZmlndXJlIGNoYW5nZSBhZnRlciB0aGUgYXBwbGljYXRpb24gb2Ygc3VydmV5IHdlaWdodHM/CiAgICArIElmIHNvLCBkZXNjcmliZSBob3cuIAorIFJlcHJvZHVjZSBgZmluYWxfcGxvdGAgYWJvdmUgZm9yIGEgZGlmZmVyZW50IGNvaG9ydCBvZiB5b3VyIGNob2ljZS4KCjwvZGl2PgoKCiMjICoqRGF0YSBBbmFseXNpcyoqCioqKiAKCiMjICoqU3VtbWFyeSoqCioqKiAKIGNvb2wgdmlzdWFsaXphdGlvbiB0aGF0IHN1bW1hcml6ZXMgZXZlcnl0aGluZy4uLiBjb3VsZCBhZGQgdGhpcyBzb21ld2hlcmU6IGh0dHBzOi8vd3d3LmZkYS5nb3YvdG9iYWNjby1wcm9kdWN0cy95b3V0aC1hbmQtdG9iYWNjby95b3V0aC10b2JhY2NvLXVzZS1yZXN1bHRzLW5hdGlvbmFsLXlvdXRoLXRvYmFjY28tc3VydmV5CgoKIyMgKipIZWxwZnVsIExpbmtzKioKKioqIAoKCiMjICoqU2Vzc2lvbiBpbmZvKioKKioqCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGA=